diff --git a/addons/sourcemod/data/l4d_hats.cfg b/addons/sourcemod/data/l4d_hats.cfg new file mode 100644 index 000000000..6b346b950 --- /dev/null +++ b/addons/sourcemod/data/l4d_hats.cfg @@ -0,0 +1,686 @@ +"Models" +{ + "1" + { + "mod" "models/infected/gibs/gibs.mdl" + "loc" "2.000000 0.500000 0.500000" + "Name" "Hand Gib" + } + "2" + { + "mod" "models/infected/limbs/exploded_boomer_head.mdl" + "Name" "Boomer Head" + } + "3" + { + "mod" "models/infected/limbs/limb_male_head01.mdl" + "loc" "0.000000 0.000000 -5.000000" + "Name" "Head Gib" + } + "4" + { + "mod" "models/props/cs_militia/circularsaw01.mdl" + "loc" "-4.000000 1.500000 1.500000" + "ang" "0.000000 80.000000 0.000000" + "Name" "Circular Saw" + } + "5" + { + "mod" "models/props/de_nuke/emergency_lighta.mdl" + "loc" "-8.000000 -0.500000 11.500000" + "ang" "-30.000000 0.000000 0.000000" + "Name" "Red Emergency Light" + } + "6" + { + "mod" "models/props_fairgrounds/alligator.mdl" + "loc" "-3.000000 0.500000 0.500000" + "Name" "Alligator" + } + "7" + { + "mod" "models/props_fairgrounds/mr_mustachio.mdl" + "loc" "-2.000000 0.000000 5.000000" + "Name" "Mr Mustachio" + } + "8" + { + "mod" "models/props_fortifications/orange_cone001_clientside.mdl" + "ang" "0.000000 60.000000 -40.000000" + "loc" "-3.000000 0.000000 1.000000" + "Name" "Traffic Cone" + } + "9" + { + "mod" "models/props_interiors/teddy_bear.mdl" + "loc" "-10.000000 0.000000 8.000000" + "ang" "-10.000000 0.000000 0.000000" + "Name" "Teddy Bear" + } + "10" + { + "mod" "models/props_interiors/toilet_b_breakable01_part13.mdl" + "loc" "-34.000000 0.500000 -14.000000" + "Name" "Toilet Seat" + } + "11" + { + "mod" "models/props_interiors/waterbottle.mdl" + "ang" "180.000000 60.000000 0.000000" + "loc" "-2.500000 -0.500000 26.000000" + "Name" "Water bottle" + } + "12" + { + "mod" "models/props_urban/dock_pylon_cap001.mdl" + "loc" "-4.000000 0.000000 10.500000" + "Name" "Dock Pylon" + } + "13" + { + "mod" "models/props_urban/life_ring001.mdl" + "loc" "-2.500000 1.000000 6.000000" + "Name" "Life Ring" + } + "14" + { + "mod" "models/props_lighting/light_construction02.mdl" + "ang" "-200.000000 0.000000 0.000000" + "loc" "-7.000000 0.000000 9.000000" + "Name" "Construction Light" + } + "15" + { + "mod" "models/extras/info_speech.mdl" + "loc" "-3.500000 0.000000 18.500000" + "Name" "Speech Quote" + } + "16" + { + "mod" "models/infected/smoker_tongue_attach.mdl" + "ang" "0.000000 -60.000000 180.000000" + "loc" "-5.500000 -2.500000 48.000000" + "Name" "Smoker Tongue" + } + "17" + { + "mod" "models/props/de_inferno/ceiling_fan_blade.mdl" + "loc" "-2.000000 -0.500000 6.000000" + "ang" "0.000000 40.000000 0.000000" + "Name" "Ceiling Fan Blades" + } + "18" + { + "mod" "models/f18/f18_placeholder.mdl" + "ang" "0.000000 180.000000 0.000000" + "loc" "-5.500000 0.000000 6.000000" + "Name" "F-18 Jet Plane" + } + "19" + { + "mod" "models/deadbodies/dead_male_civilian_radio.mdl" + "ang" "30.000000 10.000000 -60.000000" + "loc" "-3.000000 -7.000000 -1.000000" + "Name" "Civilian Radio" + } + "20" + { + "mod" "models/infected/cim_riot_faceplate.mdl" + "ang" "90.000000 0.000000 0.000000" + "loc" "-5.500000 0.000000 -66.000000" + "Name" "Riot Faceplate" + } + "21" + { + "mod" "models/props_interiors/styrofoam_cups.mdl" + "ang" "-20.000000 0.000000 0.000000" + "loc" "-9.000000 0.000000 18.000000" + "Name" "Styrofoam Cups" + } + "22" + { + "mod" "models/props_shacks/bug_lamp01.mdl" + "ang" "0.000000 180.000000 0.000000" + "loc" "-4.000000 0.000000 5.500000" + "Name" "Bug Lamp Zapper" + } + "23" + { + "mod" "models/props_unique/grill_campground.mdl" + "ang" "0.000000 180.000000 0.000000" + "loc" "-3.500000 0.000000 -30.000000" + "Name" "BBQ Grill" + } + "24" + { + "mod" "models/props_unique/luggagecart01.mdl" + "ang" "90.000000 0.000000 0.000000" + "loc" "-20.000000 0.000000 -9.000000" + "Name" "Luggage Cart" + } + "25" + { + "mod" "models/props_unique/spawn_apartment/lantern.mdl" + "loc" "-4.000000 0.000000 5.500000" + "Name" "Lantern" + } + "26" + { + "mod" "models/props_urban/exit_sign002.mdl" + "loc" "-4.000000 0.000000 12.500000" + "Name" "Exit Sign" + } + "27" + { + "mod" "models/props_urban/garden_hose001.mdl" + "ang" "40.000000 0.000000 0.000000" + "loc" "-8.000000 0.000000 2.500000" + "Name" "Garden Hose" + } + "28" + { + "mod" "models/props_urban/plastic_flamingo001.mdl" + "loc" "-5.500000 0.000000 -12.000000" + "ang" "0.000000 0.000000 0.000000" + "Name" "Pink Flamingo" + } + "29" + { + "mod" "models/props_waterfront/money_pile.mdl" + "ang" "-20.000000 0.000000 0.000000" + "loc" "-6.000000 9.000000 5.000000" + "Name" "Money Pile" + } + "30" + { + "mod" "models/props_fairgrounds/elephant.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-2.500000 0.000000 6.500000" + "Name" "Elephant" + } + "31" + { + "mod" "models/props_fairgrounds/giraffe.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-2.500000 0.000000 3.500000" + "Name" "Giraffe" + } + "32" + { + "mod" "models/props_fairgrounds/garbage_popcorn_box.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-4.000000 0.000000 7.000000" + "Name" "Popcorn Box" + } + "33" + { + "mod" "models/props_fairgrounds/gnome_closet.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-8.500000 -9.000000 -20.000000" + "Name" "Gnome Closet" + } + "34" + { + "mod" "models/props_fairgrounds/snake.mdl" + "ang" "-80.000000 0.000000 0.000000" + "loc" "-10.000000 -5.500000 -37.500000" + "Name" "Snake" + } + "35" + { + "mod" "models/props_interiors/toaster.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-4.500000 0.000000 7.500000" + "Name" "Toaster" + } + "36" + { + "mod" "models/props_unique/doll01.mdl" + "ang" "60.000000 0.000000 0.000000" + "loc" "-6.000000 0.000000 8.500000" + "Name" "Doll" + } + "37" + { + "mod" "models/props_junk/garbage_hubcap01a.mdl" + "ang" "-30.000000 0.000000 0.000000" + "loc" "-6.500000 0.000000 8.500000" + "Name" "Hub Cap" + } + "38" + { + "mod" "models/props_mall/mall_mannequin_rhand.mdl" + "ang" "60.000000 30.000000 70.000000" + "loc" "-5.500000 5.500000 6.500000" + "Name" "Mannequin Hand" + } + "39" + { + "mod" "models/props_lab/desklamp01.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-11.500000 0.000000 6.000000" + "Name" "Desk Lamp" + } + "40" + { + "mod" "models/hybridphysx/news_helicoptor_map1_intro_v1.mdl" + "ang" "0.000000 10.000000 0.000000" + "loc" "21.000000 6.000000 -0.500000" + "Name" "News Helicopter" + "size" "0.060000" + } + "41" + { + "mod" "models/missiles/f18_agm65maverick.mdl" + "ang" "10.000000 0.000000 0.000000" + "loc" "-19.000000 1.000000 8.500000" + "Name" "Missile" + "size" "0.200000" + } + "42" + { + "mod" "models/props_vehicles/boat_fishing02.mdl" + "ang" "0.000000 -90.000000 0.000000" + "loc" "-5.500000 0.000000 8.500000" + "Name" "Fishing Boat" + "size" "0.040000" + } + "43" + { + "mod" "models/props_urban/big_wheel001.mdl" + "ang" "-130.000000 -190.000000 10.000000" + "loc" "-6.000000 -1.000000 16.000000" + "Name" "Childs Trike" + "size" "0.060000" + } + "44" + { + "mod" "models/props_interiors/mounteddeerhead01.mdl" + "ang" "-20.000000 -10.000000 0.000000" + "loc" "-7.500000 1.000000 -0.500000" + "Name" "Deer Head" + "size" "0.060000" + } + "45" + { + "mod" "models/props_misc/pot-1.mdl" + "ang" "150.000000 10.000000 10.000000" + "loc" "-4.500000 1.000000 3.500000" + "Name" "Saucepan" + "size" "0.060000" + } + "46" + { + "mod" "models/props_c17/metalpot002a.mdl" + "ang" "10.000000 150.000000 -200.000000" + "loc" "0.000000 -3.000000 4.500000" + "Name" "Frying Pan" + } + "47" + { + "mod" "models/gibs/hgibs.mdl" + "ang" "10.000000 0.000000 0.000000" + "loc" "-0.500000 0.000000 0.500000" + "Name" "Skull" + } + "48" + { + "mod" "models/props/cs_militia/caseofbeer01.mdl" + "ang" "-160.000000 0.000000 180.000000" + "loc" "-4.000000 0.000000 -5.500000" + "Name" "Case of Beer" + } + "49" + { + "mod" "models/props/cs_office/chair_office.mdl" + "ang" "0.000000 0.000000 180.000000" + "loc" "-4.000000 0.000000 24.500000" + "Name" "Office Chair" + } + "50" + { + "mod" "models/props_cemetery/crypts_top02.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-4.000000 0.000000 3.000000" + "Name" "Graveyard Cross" + } + "51" + { + "mod" "models/props_fairgrounds/kiddyland_riderocket_small.mdl" + "ang" "0.000000 100.000000 0.000000" + "loc" "-4.000000 0.000000 0.500000" + "Name" "Kiddyland Rocket" + "size" "0.230000" + } + "52" + { + "mod" "models/props_interiors/toilet_b_breakable01.mdl" + "ang" "0.000000 0.000000 180.000000" + "loc" "-29.500000 1.000000 20.500000" + "Name" "Toilet" + } + "53" + { + "mod" "models/props_misc/lamp-1_gib1.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-4.500000 1.000000 -13.000000" + "Name" "Lamp Shade" + } + "54" + { + "mod" "models/props_misc/saddle-1.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-5.500000 1.000000 -15.500000" + "Name" "Saddle" + } + "55" + { + "mod" "models/props_unique/wheelchair01.mdl" + "ang" "0.000000 0.000000 180.000000" + "loc" "-4.000000 0.000000 24.500000" + "Name" "Wheel Chair" + } + "56" + { + "mod" "models/props_urban/mega_phone001.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-16.500000 -0.500000 6.500000" + "Name" "Mega Phone" + } + "57" + { + "mod" "models/props/de_train/de_train_floodlights_01.mdl" + "ang" "-90.000000 -540.000000 -180.000000" + "loc" "-4.500000 0.000000 0.000000" + "Name" "Flood lights" + } + "58" + { + "mod" "models/props_vehicles/tire001c_car.mdl" + "ang" "50.000000 0.000000 0.000000" + "loc" "-4.000000 0.000000 1.500000" + "Name" "Car Tire" + } + "59" + { + "mod" "models/props/de_inferno/ceiling_fan.mdl" + "ang" "0.000000 0.000000 -180.000000" + "loc" "-3.000000 0.000000 2.000000" + "Name" "Ceiling Fan" + } + "60" + { + "mod" "models/props/de_prodigy/fan.mdl" + "ang" "0.000000 10.000000 0.000000" + "loc" "-3.000000 0.000000 5.500000" + "Name" "Fan" + } + "61" + { + "mod" "models/props_foliage/urban_pot_clay01.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-4.500000 0.500000 -6.500000" + "Name" "Pot Plant 1" + } + "62" + { + "mod" "models/props_foliage/urban_pot_clay02.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-5.000000 -0.500000 -5.500000" + "Name" "Pot Plant 2" + } + "63" + { + "mod" "models/props_downtown/ironing_board_flat.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-15.000000 0.000000 -23.500000" + "Name" "Ironing Board" + } + "64" + { + "mod" "models/props_collectables/coin.mdl" + "ang" "30.000000 -10.000000 -10.000000" + "loc" "-14.000000 -1.000000 -6.000000" + "Name" "Coin" + "size" "1.730000" + } + "65" + { + "mod" "models/infected/jockey.mdl" + "ang" "0.000000 0.000000 0.000000" + "loc" "-7.000000 0.000000 -6.000000" + "Name" "Jockey" + "size" "0.330000" + } + "66" + { + "mod" "models/items/l4d_gift.mdl" + "ang" "-10.000000 30.000000 -30.000000" + "loc" "-4.000000 0.000000 2.000000" + "Name" "Gift" + "size" "0.530000" + } + "67" + { + "mod" "models/props_street/firehydrant.mdl" + "ang" "-20.000000 0.000000 0.000000" + "loc" "-3.000000 0.000000 -2.500000" + "Name" "Fire Hydrant" + } + "68" + { + "mod" "models/props_junk/gnome.mdl" + "ang" "0.000000 -200.000000 0.000000" + "loc" "-6.500000 5.000000 9.000000" + "Name" "Gnome" + "size" "0.530000" + } + "69" + { + "mod" "models/bunny/b_sailboat.mdl" + "ang" "-10.000000 0.000000 0.000000" + "loc" "-4.500000 0.000000 4.000000" + "Name" "Sail Boat" + "size" "0.030000" + } + "70" + { + "mod" "models/props/de_nuke/light_red2.mdl" + "ang" "10.000000 -180.000000 180.000000" + "loc" "-5.500000 0.500000 3.000000" + "Name" "Red Bulkhead Light" + "size" "0.530000" + } + "71" + { + "mod" "models/props_buildables/mine.mdl" + "ang" "20.000000 -140.000000 20.000000" + "loc" "-4.000000 0.500000 3.000000" + "Name" "Wheel Hubcap" + "size" "1.230000" + } + "72" + { + "mod" "models/props_cemetery/crypts_top01.mdl" + "ang" "10.000000 -190.000000 0.000000" + "loc" "-2.500000 1.000000 0.500000" + "Name" "Graveyard Cross" + "size" "0.030000" + } + "73" + { + "mod" "models/props_misc/tea_pot-1.mdl" + "ang" "0.000000 -90.000000 30.000000" + "loc" "-3.000000 0.000000 4.000000" + "Name" "Tea Pot" + "size" "0.500000" + } + "74" + { + "mod" "models/props_fairgrounds/pyrotechnics_launcher.mdl" + "ang" "0.000000 -90.000000 20.000000" + "loc" "-4.000000 0.000000 1.000000" + "Name" "Pyrotechnics" + "size" "0.500000" + } + "75" + { + "mod" "models/props_interiors/coffee_maker.mdl" + "ang" "-10.000000 -10.000000 0.000000" + "loc" "-3.500000 0.000000 1.500000" + "Name" "Coffee Maker" + "size" "0.500000" + } + "76" + { + "mod" "models/props_interiors/pot01a.mdl" + "ang" "0.000000 -360.000000 0.000000" + "loc" "-3.500000 0.000000 6.000000" + "Name" "Kettle" + "size" "-0.100000" + } + "77" + { + "mod" "models/props_interiors/tv.mdl" + "ang" "0.000000 -280.000000 0.000000" + "loc" "-3.000000 0.000000 -6.000000" + "Name" "TV" + "size" "0.500000" + } + "78" + { + "mod" "models/props_interiors/lamp_floor_gib2.mdl" + "ang" "10.000000 -290.000000 -30.000000" + "loc" "27.000000 -21.500000 -62.000000" + "Name" "Lamp Shade 1" + "size" "0.500000" + } + "79" + { + "mod" "models/props_interiors/lamp_table02_gib2.mdl" + "ang" "0.000000 -280.000000 -40.000000" + "loc" "8.000000 -1.500000 -14.000000" + "Name" "Lamp Shade 2" + "size" "0.500000" + } + "80" + { + "mod" "models/props_lighting/semi_flush_001.mdl" + "ang" "0.000000 -280.000000 170.000000" + "loc" "-4.000000 0.000000 2.000000" + "Name" "Lamp Shade 3" + "size" "0.000000" + } + "81" + { + "mod" "models/props_junk/petfoodbag01.mdl" + "ang" "-50.000000 -180.000000 10.000000" + "loc" "-15.500000 -1.500000 -5.500000" + "Name" "Dog Food" + "size" "0.000000" + } + "82" + { + "mod" "models/props_lighting/flashlight_dropped_01.mdl" + "ang" "0.000000 -280.000000 170.000000" + "loc" "1.000000 -0.500000 4.000000" + "Name" "Dalek Flash Light" + "size" "0.500000" + } + "83" + { + "mod" "models/props_lighting/lightfixture03.mdl" + "ang" "-50.000000 -550.000000 -170.000000" + "loc" "3.000000 -1.500000 -8.000000" + "Name" "Ball Light" + "size" "0.500000" + } + "84" + { + "mod" "models/props_mall/cash_register.mdl" + "ang" "-10.000000 -360.000000 0.000000" + "loc" "-3.000000 0.000000 1.000000" + "Name" "Cash Register" + "size" "0.000000" + } + "85" + { + "mod" "models/props_placeable/tier1_guns_trophy.mdl" + "ang" "0.000000 -280.000000 0.000000" + "loc" "-3.500000 0.000000 1.500000" + "Name" "Gun Trophy 1" + "size" "0.700000" + } + "86" + { + "mod" "models/props_placeable/tier2_guns_trophy.mdl" + "ang" "10.000000 -270.000000 0.000000" + "loc" "-4.500000 -0.500000 -0.500000" + "Name" "Gun Trophy 2" + "size" "0.800000" + } + "87" + { + "mod" "models/weapons/arms/v_spitter_arms.mdl" + "ang" "-70.000000 0.000000 10.000000" + "loc" "-6.500000 -0.500000 1.500000" + "Name" "Spitter Arms" + "size" "0.300000" + } + "88" + { + "mod" "models/weapons/arms/v_jockey_arms.mdl" + "ang" "-70.000000 0.000000 10.000000" + "loc" "-7.500000 -0.500000 1.500000" + "Name" "Jockey Claws" + "size" "0.300000" + } + "89" + { + "mod" "models/v_models/weapons/v_claw_hulk.mdl" + "ang" "310.000000 540.000000 190.000000" + "loc" "-6.000000 0.000000 5.000000" + "Name" "Tank Claws" + "size" "0.200000" + } + "90" + { + "mod" "models/w_models/weapons/w_he_grenade.mdl" + "ang" "-20.000000 0.000000 10.000000" + "loc" "-3.500000 0.000000 5.500000" + "Name" "Grenade Shell" + "size" "2.300000" + } + "91" + { + "mod" "models/props_junk/propanecanister001a.mdl" + "ang" "10.000000 10.000000 0.000000" + "loc" "5.000000 -4.500000 1.000000" + "Name" "Propane Cylinder" + "size" "0.800000" + } + "92" + { + "mod" "models/w_models/weapons/w_eq_medkit.mdl" + "ang" "120.000000 -190.000000 260.000000" + "loc" "-5.000000 4.500000 2.000000" + "Name" "Medkit Cap" + "size" "1.100000" + } + "93" + { + "mod" "models/weapons/melee/w_riotshield.mdl" + "ang" "-10.000000 0.000000 0.000000" + "loc" "2.000000 -2.000000 0.000000" + "Name" "Riot Shield" + "size" "0.400000" + } + "94" + { + "mod" "models/props_skybox/boat_rescue_tug_sunshine.mdl" + "ang" "20.000000 -180.000000 0.000000" + "loc" "-3.500000 0.500000 2.500000" + "Name" "Tug Boat" + "size" "1.100000" + } +} diff --git a/addons/sourcemod/plugins/optional/l4d_hats.smx b/addons/sourcemod/plugins/optional/l4d_hats.smx new file mode 100644 index 000000000..c3a89d2e8 Binary files /dev/null and b/addons/sourcemod/plugins/optional/l4d_hats.smx differ diff --git a/addons/sourcemod/scripting/l4d_hats.sp b/addons/sourcemod/scripting/l4d_hats.sp new file mode 100644 index 000000000..3c8192335 --- /dev/null +++ b/addons/sourcemod/scripting/l4d_hats.sp @@ -0,0 +1,3185 @@ +/* +* Hats +* Copyright (C) 2024 Silvers +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + + + +#define PLUGIN_VERSION "1.51" + +/*====================================================================================== + Plugin Info: + +* Name : [L4D & L4D2] Hats +* Author : SilverShot +* Descrp : Attaches specified models to players above their head. +* Link : https://forums.alliedmods.net/showthread.php?t=153781 +* Plugins : https://sourcemod.net/plugins.php?exact=exact&sortby=title&search=1&author=Silvers + +======================================================================================== + Change Log: + +1.51 (31-May-2024) + - Fixed client not in game errors being thrown on player death. Thanks to "lzvs" for reporting. + - Fixed invalid entity errors being thrown. Thanks to "Voevoda" for reporting. + - Added Spanish translations. Thanks to "lechuga" for providing. + +1.50 (12-Mar-2024) + - Added a thirdperson camera detection for "m_hViewEntity". Thanks to "Marttt" for reporting. + - More fixes to keep the hat visible when changing between thirdperson modes (events, cvar, TP plugin). Thanks to "Yabi" for reporting. + +1.49 (27-Nov-2023) + - Fixed the hat showing when being healed by someone else. + - Fixed hats randomly showing in first person. Thanks to "Yabi" for reporting. + - Fixed the "l4d_hats_random" value "2" not saving across map changes. Thanks to "Yabi" for reporting. + +1.48 (24-Nov-2023) + - Fixed the hat showing after staggering when the stagger timer didn't reset (due to some plugins such as "Stagger Gravity"). + +1.47 (22-Nov-2023) + - Now shows hats in 3rd person view when healing someone, using a generator or opening a footlocker, and possibly more situations. Thanks to "Voevoda" for reporting. + - Fixed invalid handle errors caused by the last update. Should have worked, seems to be some weirdness with SourceMod. Thanks to "Voevoda" for reporting and "HarryPotter" for help. + +1.46 (07-Nov-2023) + - Now shows hats in 3rd person view when deploying upgrade ammo packs, staggering or recovering from a pounce/charge. Thanks to "Voevoda" for reporting. + +1.45a (27-Aug-2022) + - Updated "Russian" translation file. Thanks to "A1ekin" for making changes. + +1.45 (29-May-2022) + - Added public command "sm_hats" to display a menu of hat options. Thanks to "pan0s" for writing. + - Added public command "sm_hatall" to toggle the visibility of everyone's hats. Requested by "LordVGames". + - Added admin command "sm_hatallc" to toggle a clients visibility hats. Requested by "Krevik". + + - Added saving a players visibility of all hats from the new commands above. + - Added changes by "pan0s" to save the first and third person view of hats status. + - Added a new colors stock for printing text, supports {RED} and {BLUE} colors. Thanks to "pan0s" for providing. + - Added support for the "Ready-Up" plugin to hide or show the panel when using the Hats menu. Requested by "Krevik". + + - Changed commands "sm_hatshow", "sm_hatshowon" and "sm_hatshowoff" to only affect 1st person view, and 3rd person view with an optional argument "tp". + - Fixed crashing if a model was missing. Plugin now fails to load forcing a config fix. Thanks to "Dragokas" for reporting. + - Fixed hats not saving depending on the "l4d_hats_make" cvar value. + + - Thanks to "Krevik" and "pan0s" for help lots of help and testing. + - Thanks to "pan0s" for updating the Chinese translations. + - Thanks to "Impact" for updating the German translations. + - Thanks to "Dragokas" for updating the Russian and Ukrainian translations. + + - Translation files have updated. Please update or errors will occur and the plugin won't work. + +1.44 (15-Apr-2022) + - Changed command "sm_hat" to accept 3 letter or smaller words for partial matching, e.g. "sm_hat saw". + - Fixed command "sm_hatdel" not deleting the whole entry. + - Fixed command "sm_hat" changing other players hats after using "sm_hatc" command. Thanks to "kot4404" for reporting. + - Removed the "Big Helicopter" model from the data config. Too many reports of client-side glowing sprites remaining behind. + +1.43 (06-Feb-2022) + - Added a hackish fix for L4D2 not precaching models properly which has been causing stutter when using a model for the first time. + - Fixed menus closing when selecting a player with a userid greater than 999. Thanks to "Electr000999" for reporting. + +1.42 (16-Dec-2021) + - Fixed simple mistake from last update causing wrong menu listing when not using a "hatnames" translation. Thanks to "Mi.Cura" for reporting. + +1.41 (14-Dec-2021) + - Fixed spawning and respawning with a hat when it was turned off. Thanks to "kot4404" for reporting. + + - Changed the "hatnames.phrases.txt" translation file format for better modifications when adding or removing hats from the data config. + - Now supports adding hats and breaking the plugin when missing from the "hatnames.phrases.txt" translations file. + - New "hatnames" translations no longer uses indexes and only model names. + - Still supports the old version but suggest upgrading to the new. + - Included the script for converting the translation file based on the config. Search for "TRANSLATE CODE" in the source. + +1.40 (11-Dec-2021) + - Fixed not saving hat angles and origins correctly when "l4d_hats_wall" was set to "0". Thanks to "NoroHime" for reporting. + - Now saves when a hat was removed, if saving is enabled. Requested by "kot4404". + +1.39 (09-Dec-2021) + - Changed command "sm_hat" to accept "rand" or "random" as a parameter option to give a random hat. + - Updated the "chi" and "zho" translation "hatnames.phrases.txt" files to be correct. Thanks to "NoroHime". + +1.38 (03-Dec-2021) + - Added "Hat_Off" option to the menu. Requested by "kot4404". + - Fixed command "sm_hatadd" from not adding new entries. Thanks to "swiftswing1" for reporting. + - Changes to fix warnings when compiling on SourceMod 1.11. + +1.37 (09-Sep-2021) + - Plugin now deletes the client cookie and hat if they no longer have access to use hats. Requested by "Darkwob". + +1.36 (20-Jul-2021) + - Removed cvar "l4d_hats_view" - recommended to use "ThirdPersonShoulder_Detect" plugin to turn on/off the hat view when in 3rd/1st person view. + +1.35 (10-Jul-2021) + - Fixed giving random hats to players when the "l4d_hats_random" cvar was set to "0". Thanks to "XYZC" for reporting. + +1.34 (05-Jul-2021) + - Fixed giving random hats on round_start when "l4d_hats_save" cvar was set to "1". + +1.33 (04-Jul-2021) + - Fixed "sm_hatrand" and "sm_hatrandom" from not giving random hats. Not sure when this broke. + +1.32 (01-Jul-2021) + - Added a warning message to suggest installing the "Attachments API" and "Use Priority Patch" plugins if missing. + +1.31 (03-May-2021) + - Added Simplified Chinese (zho) and Traditional Chinese (chi) translations. Thanks to "pan0s" for providing. + - Fixed not giving random hats to clients who have no saved hats. Thanks to "pan0s" for reporting. + +1.30 (28-Apr-2021) + - Fixed client not in-game errors. Thanks to "HarryPotter" for reporting. + +1.29 (10-Apr-2021) + - Added cvar "l4d_hats_bots" to allow or disallow bots from spawning with hats. + - Added cvar "l4d_hats_make" to allow players with specific flags only to auto spawn with hats. + +1.28 (20-Mar-2021) + - Added cvar "l4d_hats_wall" to prevent hats glowing through walls. Thanks to "Marttt" for the method and "Dragokas" for requesting. + - Fixed personal hats not showing when changing hat in external view. + +1.27 (01-Mar-2021) + - Fixed invalid client errors due to the last update. Thanks to "ur5efj" for reporting. + +1.26 (01-Mar-2021) + - Now blocks showing hats when spectating someone in first person view. Thanks to "Alex101192" for reporting. + +1.25 (23-Feb-2021) + - Fixed hats not hiding after being revived. Thanks to "Alex101192" for reporting. + +1.24 (01-Oct-2020) + - Changed "l4d_hats_precache" cvar default value to blank. + - Changed the way "l4d_hats_detect" works. Now also detects if reviving someone (events were unreliable and causing bugs). + - Fixed 1st and 3rd person view of hats wrongfully toggling under certain conditions. Thanks to "Alex101192" for reporting. + - Fixed some spelling mistakes in the "data/l4d_hats.cfg" hat names. + +1.23 (16-Jun-2020) + - Added Russian and Ukrainian translations - Thanks to "Dragokas" for providing. + - Fixed changing hats when "l4d_hats_save" and "l4d_hats_random" were set. Random is superseded by saved if present. + - Fixed command "sm_hatclient" throwing an error when only a client was specified. + - Fixed hat view "ThirdPersonShoulder_Detect" and "Survivor Thirdperson" plugins clashing. + +1.22 (10-May-2020) + - Extra checks to prevent "IsAllowedGameMode" throwing errors. + - Fixed not always loading client cookies before creating hats. Thanks to "Alex101192" for reporting. + - Fixed potentially not translating some strings. + - Fixed some functions not working for more than 100 hats. + - Fixed hats affecting Survivor Thirdperson view under certain conditions. + - Various changes to tidy up code. + - Various optimizations and fixes. + +1.21 (30-Apr-2020) + - Added cvar "l4d_hats_detect" to enable clients to see their own hat when 3rd person view is detected. + - Optionally uses "ThirdPersonShoulder_Detect" plugin by "Lux" and "MasterMind420", if available. + + - Added bunch of maps to the default value of "l4d_hats_precache". Thanks to "Alex101192" for providing. + - Increased "l4d_hats_precache" cvar length, max usable length 490 (due to game limitations). + +1.20 (01-Apr-2020) + - Fixed "IsAllowedGameMode" from throwing errors when the "_tog" cvar was changed before MapStart. + - Removed "colors.inc" dependency. + - Updated these translation file encodings to UTF-8 (to display all characters correctly): German (de). + +1.19 (19-Dec-2019) + - Added command "sm_hatclient" to set a clients hat, requested by "foxhound27". + +1.18 (23-Oct-2019) + - Added commands "sm_hatshowon" and "sm_hatshowoff" to turn on/off personal hat visibility. + - Fixed cvar "l4d_hats_precache" from modifying the allow cvar. Now correctly disables on blocked maps. + +1.17 (10-Sep-2019) + - Added cvar "l4d_hats_precache" to prevent pre-caching models on specified maps. + +1.17b (19-Aug-2019) + - Fixed ghosts from having hats. + +1.16 (02-Aug-2019) + - Fixed "m_TimeForceExternalView not found" error for L4D1 - Thanks to "Ja-Forces" for reporting. + +1.15 (05-May-2018) + - Converted plugin source to the latest syntax utilizing methodmaps. Requires SourceMod 1.8 or newer. + - Changed cvar "l4d_hats_modes_tog" now supports L4D1. + +1.14 (25-Jun-2017) + - Added "Reset" option to the ang/pos/size menus, requested by "ZBzibing". + - Fixed depreciated FCVAR_PLUGIN and GetClientAuthString. + - Increased MAX_HATS value and added many extra L4D2 hats thanks to "Munch". + +1.13 (29-Mar-2015) + - Fixed the plugin not working in L4D1 due to a SetEntPropFloat property not found error. + +1.12 (07-Oct-2012) + - Fixed hats blocking players +USE by adding a single line of code - Thanks to "Machine". + +1.11 (02-Jul-2012) + - Fixed cvar "l4d_hats_random" from not working properly - Thanks to "Don't Fear The Reaper" for reporting. + +1.10 (20-Jun-2012) + - Added German translations - Thanks to "Don't Fear The Reaper". + - Small fixes. + +1.9.0 (22-May-2012) + - Fixed multiple hat changes only showing the first hat to players. + - Changing hats will no longer return the player to firstperson if thirdperson was already on. + +1.8.0 (21-May-2012) + - Fixed command "sm_hatc" making the client thirdpeson and not the target. + +1.7.0 (20-May-2012) + - Added cvar "l4d_hats_change" to put the player into thirdperson view when they select a hat, requested by "disawar1". + +1.6.1 (15-May-2012) + - Fixed a bug when printing to chat after changing someones hat. + - Fixed cvar "l4d_hats_menu" not allowing access if it was empty. + +1.6.0 (15-May-2012) + - Fixed the allow cvars not affecting everything. + +1.5.0 (10-May-2012) + - Added translations, required for the commands and menu title. + - Added optional translations for the hat names as requested by disawar1. + - Added cvar "l4d_hats_allow" to turn on/off the plugin. + - Added cvar "l4d_hats_modes" to control which game modes the plugin works in. + - Added cvar "l4d_hats_modes_off" same as above. + - Added cvar "l4d_hats_modes_tog" same as above, but only works for L4D2. + - Added cvar "l4d_hats_save" to save a players hat for next time they spawn or connect. + - Added command "sm_hatsize" to change the scale/size of hats as suggested by worminater. + - Fixed "l4d_hats_menu" flags not setting correctly. + - Optimized the plugin by hooking cvar changes. + - Selecting a hat from the menu no longer returns to the first page. + +1.4.3 (07-May-2011) + - Added "name" key to the config for reading hat names. + +1.4.2 (16-Apr-2011) + - Changed the way models are checked to exist and precached. + +1.4.1 (16-Apr-2011) + - Added new hat models to the config. Deleted and repositioned models blocking the "use" function. + - Changed the hat entity from prop_dynamic to prop_dynamic_override (allows physics models to be attached). + - Fixed command "sm_hatadd" causing crashes due to models not being pre-cached, cannot cache during a round, causes crash. + - Fixed pre-caching models which are missing (logs an error telling you an incorrect model is specified). + +1.4.0 (11-Apr-2011) + - Added cvar "l4d_hats_opaque" to set hat transparency. + - Changed cvar "l4d_hats_random" to create a random hat when survivors spawn. 0=Never. 1=On round start. 2=Only first spawn (keeps the same hat next round). + - Fixed hats changing when returning from idle. + - Replaced underscores (_) with spaces in the menu. + +1.3.4 (09-Apr-2011) + - Fixed hooking L4D2 events in L4D1. + +1.3.3 (07-Apr-2011) + - Fixed command "sm_hatc" not displaying for admins when they are dead/infected team. + - Minor bug fixes. + +1.3.2 (06-Apr-2011) + - Fixed command "sm_hatc" displaying invalid player. + +1.3.1 (05-Apr-2011) + - Fixed the fix of command "sm_hat" flags not applying. + +1.3.0 (05-Apr-2011) + - Fixed command "sm_hat" flags not applying. + +1.2.0 (03-Apr-2011) + - Added command "sm_hatoffc" for admins to disable hats on specific clients. + - Added cvar "l4d_hats_third" to control the previous update's addition. + +1.1.1a (03-Apr-2011) + - Added events to show / hide the hat when in third / first person view. + +1.1.1 (02-Apr-2011) + - Added cvar "l4d_hats_view" to toggle if a players hat is visible by default when they join. + - Resets variables for clients when they connect. + +1.1.0 (01-Apr-2011) + - Added command "sm_hatoff" - Toggle to turn on or off the ability of wearing hats. + - Added command "sm_hatadd" - To add models into the config. + - Added command "sm_hatdel" - To remove a model from the config. + - Added command "sm_hatlist" - To display a list of all models (for use with sm_hatdel). + +1.0.0 (29-Mar-2011) + - Initial release. + +======================================================================================*/ + +#pragma semicolon 1 + +#pragma newdecls required +#include +#include +#include +#include + +#define CVAR_FLAGS FCVAR_NOTIFY +#define CONFIG_SPAWNS "data/l4d_hats.cfg" +#define MAX_HATS 128 + + + +////////////////////////////////// +// Updated by pan0s +// #include +Handle g_hCookie_ThirdView, g_hCookie_FirstView; +bool g_bIsThirdPerson[MAXPLAYERS+1]; // View on TP +bool g_bHatViewTP[MAXPLAYERS+1]; // View on TP +////////////////////////////////// + +ConVar g_hCvarAllow, g_hCvarBots, g_hCvarChange, g_hCvarDetect, g_hCvarMake, g_hCvarMenu, g_hCvarModes, g_hCvarModesOff, g_hCvarModesTog, g_hCvarOpaq, g_hCvarPrecache, g_hCvarRand, g_hCvarSave, g_hCvarThird, g_hCvarWall; +ConVar g_hCvarMPGameMode, g_hPluginReadyUp; +Handle g_hCookie_Hat, g_hCookie_All; +Menu g_hMenu, g_hMenus[MAXPLAYERS+1]; +bool g_bCvarAllow, g_bMapStarted, g_bCvarBots, g_bCvarWall, g_bLeft4Dead2, g_bTranslation, g_bViewHooked, g_bValidMap; +int g_iCount, g_iCvarMake, g_iCvarMenu, g_iCvarOpaq, g_iCvarRand, g_iCvarSave, g_iCvarThird; +float g_fCvarChange, g_fCvarDetect; + +float g_fSize[MAX_HATS], g_vAng[MAX_HATS][3], g_vPos[MAX_HATS][3]; +char g_sModels[MAX_HATS][64], g_sNames[MAX_HATS][64]; +char g_sFlagsMake[32]; +char g_sFlagsMenu[32]; +char g_sSteamID[MAXPLAYERS+1][32]; // Stores client user id to determine if the blocked player is the same +int g_iHatIndex[MAXPLAYERS+1]; // Player hat entity reference +int g_iHatWalls[MAXPLAYERS+1]; // Hidden hat entity reference +int g_iSelected[MAXPLAYERS+1]; // The selected hat index (0 to MAX_HATS) +int g_iTarget[MAXPLAYERS+1]; // For admins to change clients hats +int g_iType[MAXPLAYERS+1]; // Stores selected hat to give players +int g_iMenuType[MAXPLAYERS+1]; // Admin var for menu +bool g_bHatAll[MAXPLAYERS+1] = {true, ...}; // Visibility of everyones hats (personal setting) +bool g_bHatView[MAXPLAYERS+1]; // Player view of hat on/off (personal setting) +bool g_bHatOff[MAXPLAYERS+1]; // Lets players turn their hats on/off +bool g_bBlocked[MAXPLAYERS+1]; // Determines if the player is blocked from hats +bool g_bExternalCvar[MAXPLAYERS+1]; // If thirdperson view was detected (thirdperson_shoulder cvar) +bool g_bExternalProp[MAXPLAYERS+1]; // If thirdperson view was detected (netprop or revive actions) +bool g_bExternalState[MAXPLAYERS+1]; // If thirdperson view was detected +bool g_bExternalChange[MAXPLAYERS+1]; // When changing hats, show in 3rd person +bool g_bCookieAuth[MAXPLAYERS+1]; // When cookies cached and client is authorized +Handle g_hTimerView[MAXPLAYERS+1]; // Thirdperson view when selecting hat +Handle g_hTimerDelay[MAXPLAYERS+1]; // Delayed return to 1st person +Handle g_hTimerDetect; + +// ReadyUP plugin +native bool ToggleReadyPanel(bool show, int target = 0); + + + +// ==================================================================================================== +// PLUGIN INFO / START / END +// ==================================================================================================== +public Plugin myinfo = +{ + name = "[L4D & L4D2] Hats", + author = "SilverShot", + description = "Attaches specified models to players above their head.", + version = PLUGIN_VERSION, + url = "https://forums.alliedmods.net/showthread.php?t=153781" +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + EngineVersion test = GetEngineVersion(); + if( test == Engine_Left4Dead ) g_bLeft4Dead2 = false; + else if( test == Engine_Left4Dead2 ) g_bLeft4Dead2 = true; + else + { + strcopy(error, err_max, "Plugin only supports Left 4 Dead 1 & 2."); + return APLRes_SilentFailure; + } + + MarkNativeAsOptional("ToggleReadyPanel"); + + return APLRes_Success; +} + +public void OnAllPluginsLoaded() +{ + // Attachments API + if( FindConVar("attachments_api_version") == null && (FindConVar("l4d2_swap_characters_version") != null || FindConVar("l4d_csm_version") != null) ) + { + LogMessage("\n==========\nWarning: You should install \"[ANY] Attachments API\" to fix model attachments when changing character models: https://forums.alliedmods.net/showthread.php?t=325651\n==========\n"); + } + + // Use Priority Patch + if( FindConVar("l4d_use_priority_version") == null ) + { + LogMessage("\n==========\nWarning: You should install \"[L4D & L4D2] Use Priority Patch\" to fix attached models blocking +USE action: https://forums.alliedmods.net/showthread.php?t=327511\n==========\n"); + } + + g_hPluginReadyUp = FindConVar("l4d_ready_enabled"); +} + +public void OnPluginStart() +{ + // Load config + KeyValues hFile = OpenConfig(); + char sTemp[64]; + bool message; + + for( int i = 0; i < MAX_HATS; i++ ) + { + IntToString(i+1, sTemp, sizeof(sTemp)); + if( hFile.JumpToKey(sTemp) ) + { + hFile.GetString("mod", sTemp, sizeof(sTemp)); + + TrimString(sTemp); + if( sTemp[0] == 0 ) + break; + + if( FileExists(sTemp, true) ) + { + hFile.GetVector("ang", g_vAng[i]); + hFile.GetVector("loc", g_vPos[i]); + g_fSize[i] = hFile.GetFloat("size", 1.0); + g_iCount++; + + strcopy(g_sModels[i], sizeof(g_sModels[]), sTemp); + + hFile.GetString("name", g_sNames[i], sizeof(g_sNames[])); + + if( strlen(g_sNames[i]) == 0 ) + GetHatName(g_sNames[i], i); + } + else + { + message = true; + LogError("Cannot find the model '%s'.", sTemp); + } + + hFile.Rewind(); + } + } + + if( message ) + { + SetFailState("\n==========\nWarning: Please fix your \"%s\" config. Missing models detected.\n==========\n", CONFIG_SPAWNS); + } + + delete hFile; + + if( g_iCount == 0 ) + SetFailState("No models wtf?!"); + + + + // Transactions + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "translations/hatnames.phrases.txt"); + g_bTranslation = FileExists(sPath); + + if( g_bTranslation ) + LoadTranslations("hatnames.phrases"); + LoadTranslations("hats.phrases"); + LoadTranslations("core.phrases"); + LoadTranslations("common.phrases"); + + + + // Hats menu + if( g_bTranslation == false ) + { + g_hMenu = new Menu(HatMenuHandler); + g_hMenu.AddItem("HAT_DISABLED", "HAT_DISABLED"); + + for( int i = 0; i < g_iCount; i++ ) + g_hMenu.AddItem(g_sModels[i], g_sNames[i]); + g_hMenu.SetTitle("%t", "Hat_Menu_Title"); + g_hMenu.ExitBackButton = true; + g_hMenu.ExitButton = true; + } + + + + // Cvars + g_hCvarAllow = CreateConVar( "l4d_hats_allow", "1", "0=Plugin off, 1=Plugin on.", CVAR_FLAGS ); + g_hCvarBots = CreateConVar( "l4d_hats_bots", "1", "0=Disallow bots from spawning with Hats. 1=Allow bots to spawn with hats.", CVAR_FLAGS, true, 0.0, true, 1.0 ); + g_hCvarChange = CreateConVar( "l4d_hats_change", "1.3", "0=Off. Other value puts the player into thirdperson for this many seconds when selecting a hat.", CVAR_FLAGS ); + g_hCvarDetect = CreateConVar( "l4d_hats_detect", "0.3", "0.0=Off. How often to detect thirdperson view. Also uses ThirdPersonShoulder_Detect plugin if available.", CVAR_FLAGS ); + g_hCvarMake = CreateConVar( "l4d_hats_make", "", "Specify admin flags or blank to allow all players to spawn with a hat, requires the l4d_hats_random cvar to spawn.", CVAR_FLAGS ); + g_hCvarMenu = CreateConVar( "l4d_hats_menu", "", "Specify admin flags or blank to allow all players access to the hats menu.", CVAR_FLAGS ); + g_hCvarModes = CreateConVar( "l4d_hats_modes", "", "Turn on the plugin in these game modes, separate by commas (no spaces). (Empty = all).", CVAR_FLAGS ); + g_hCvarModesOff = CreateConVar( "l4d_hats_modes_off", "", "Turn off the plugin in these game modes, separate by commas (no spaces). (Empty = none).", CVAR_FLAGS ); + g_hCvarModesTog = CreateConVar( "l4d_hats_modes_tog", "", "Turn on the plugin in these game modes. 0=All, 1=Coop, 2=Survival, 4=Versus, 8=Scavenge. Add numbers together.", CVAR_FLAGS ); + g_hCvarOpaq = CreateConVar( "l4d_hats_opaque", "255", "How transparent or solid should the hats appear. 0=Translucent, 255=Opaque.", CVAR_FLAGS, true, 0.0, true, 255.0 ); + g_hCvarPrecache = CreateConVar( "l4d_hats_precache", "", "Prevent pre-caching models on these maps, separate by commas (no spaces). Enabling plugin on these maps will crash the server.", CVAR_FLAGS ); + g_hCvarRand = CreateConVar( "l4d_hats_random", "1", "Attach a random hat when survivors spawn. 0=Never. 1=On round start. 2=Only first spawn (keeps the same hat next round).", CVAR_FLAGS, true, 0.0, true, 2.0 ); + g_hCvarSave = CreateConVar( "l4d_hats_save", "1", "0=Off, 1=Save the players selected hats and attach when they spawn or rejoin the server. Overrides the random setting.", CVAR_FLAGS, true, 0.0, true, 1.0 ); + g_hCvarThird = CreateConVar( "l4d_hats_third", "1", "0=Off, 1=When a player is in third person view, display their hat. Hide when in first person view.", CVAR_FLAGS, true, 0.0, true, 1.0 ); + g_hCvarWall = CreateConVar( "l4d_hats_wall", "1", "0=Show hats glowing through walls, 1=Hide hats glowing when behind walls (creates 1 extra entity per hat).", CVAR_FLAGS, true, 0.0, true, 1.0 ); + CreateConVar( "l4d_hats_version", PLUGIN_VERSION, "Hats plugin version.", FCVAR_NOTIFY|FCVAR_DONTRECORD); + AutoExecConfig(true, "l4d_hats"); + + g_hCvarMPGameMode = FindConVar("mp_gamemode"); + g_hCvarMPGameMode.AddChangeHook(ConVarChanged_Allow); + g_hCvarAllow.AddChangeHook(ConVarChanged_Allow); + g_hCvarModes.AddChangeHook(ConVarChanged_Allow); + g_hCvarModesOff.AddChangeHook(ConVarChanged_Allow); + g_hCvarModesTog.AddChangeHook(ConVarChanged_Allow); + g_hCvarBots.AddChangeHook(ConVarChanged_Cvars); + g_hCvarChange.AddChangeHook(ConVarChanged_Cvars); + g_hCvarDetect.AddChangeHook(ConVarChanged_Cvars); + g_hCvarMake.AddChangeHook(ConVarChanged_Cvars); + g_hCvarMenu.AddChangeHook(ConVarChanged_Cvars); + g_hCvarRand.AddChangeHook(ConVarChanged_Cvars); + g_hCvarSave.AddChangeHook(ConVarChanged_Cvars); + g_hCvarWall.AddChangeHook(ConVarChanged_Cvars); + g_hCvarOpaq.AddChangeHook(CvarChangeOpac); + g_hCvarThird.AddChangeHook(CvarChangeThird); + + + + // Commands + RegConsoleCmd("sm_hats", CmdHatMain, "Displays a menu to customize various settings for hats."); + RegConsoleCmd("sm_hat", CmdHat, "Displays a menu of hats allowing players to change what they are wearing. Optional args: [0 - 128 or hat name or \"random\"]"); + RegConsoleCmd("sm_hatoff", CmdHatOff, "Toggle to turn on or off the ability of wearing hats."); + RegConsoleCmd("sm_hatshow", CmdHatShow, "Toggle to see or hide your own hat. Applies to first person view or third person using the optional command argument \"tp\" e.g. \"sm_hatshow tp\""); + RegConsoleCmd("sm_hatview", CmdHatShow, "Toggle to see or hide your own hat. Applies to first person view or third person using the optional command argument \"tp\" e.g. \"sm_hatview tp\""); + RegConsoleCmd("sm_hatshowon", CmdHatShowOn, "See your own hat. Applies to first person view or third person using the optional command argument \"tp\" e.g. \"sm_hatshowon tp\""); + RegConsoleCmd("sm_hatshowoff", CmdHatShowOff, "Hide your own hat. Applies to first person view or third person using the optional command argument \"tp\" e.g. \"sm_hatshowoff tp\""); + RegConsoleCmd("sm_hatall", CmdHatsToggle, "Toggles the visibility of everyone's hats."); + RegAdminCmd("sm_hatclient", CmdHatClient, ADMFLAG_ROOT, "Set a clients hat. Usage: sm_hatclient <#userid|name> [hat name or hat index: 0-128 (MAX_HATS)]."); + RegAdminCmd("sm_hatoffc", CmdHatOffTarget, ADMFLAG_ROOT, "Toggle the ability of wearing hats on specific players."); + RegAdminCmd("sm_hatallc", CmdHatAllTarget, ADMFLAG_ROOT, "Toggle the visibility of all hats on specific players."); + RegAdminCmd("sm_hatc", CmdHatTarget, ADMFLAG_ROOT, "Displays a menu listing players, select one to change their hat."); + RegAdminCmd("sm_hatrandom", CmdHatRand, ADMFLAG_ROOT, "Randomizes all players hats."); + RegAdminCmd("sm_hatrand", CmdHatRand, ADMFLAG_ROOT, "Randomizes all players hats."); + RegAdminCmd("sm_hatadd", CmdHatAdd, ADMFLAG_ROOT, "Adds specified model to the config (must be the full model path)."); + RegAdminCmd("sm_hatdel", CmdHatDel, ADMFLAG_ROOT, "Removes a model from the config (either by index or partial name matching)."); + RegAdminCmd("sm_hatlist", CmdHatList, ADMFLAG_ROOT, "Displays a list of all the hat models (for use with sm_hatdel)."); + RegAdminCmd("sm_hatsave", CmdHatSave, ADMFLAG_ROOT, "Saves the hat position and angels to the hat config."); + RegAdminCmd("sm_hatload", CmdHatLoad, ADMFLAG_ROOT, "Changes all players hats to the one you have."); + RegAdminCmd("sm_hatang", CmdAng, ADMFLAG_ROOT, "Shows a menu allowing you to adjust the hat angles (affects all hats/players)."); + RegAdminCmd("sm_hatpos", CmdPos, ADMFLAG_ROOT, "Shows a menu allowing you to adjust the hat position (affects all hats/players)."); + RegAdminCmd("sm_hatsize", CmdHatSize, ADMFLAG_ROOT, "Shows a menu allowing you to adjust the hat size (affects all hats/players)."); + + g_hCookie_Hat = RegClientCookie("l4d_hats", "Hat Type", CookieAccess_Protected); + g_hCookie_All = RegClientCookie("l4d_hats_all", "General Hats Visibility", CookieAccess_Protected); + + // Updated by pan0s + g_hCookie_FirstView = RegClientCookie("l4d_hats_fv", "Hats First person View", CookieAccess_Protected); + g_hCookie_ThirdView = RegClientCookie("l4d_hats_tv", "Hats Third person View", CookieAccess_Protected); +} + +public void OnPluginEnd() +{ + for( int i = 1; i <= MaxClients; i++ ) + RemoveHat(i); +} + + + +// ==================================================================================================== +// CVARS +// ==================================================================================================== +public void OnConfigsExecuted() +{ + IsAllowed(); +} + +void ConVarChanged_Allow(Handle convar, const char[] oldValue, const char[] newValue) +{ + IsAllowed(); +} + +void ConVarChanged_Cvars(Handle convar, const char[] oldValue, const char[] newValue) +{ + GetCvars(); +} + +void GetCvars() +{ + g_hCvarMake.GetString(g_sFlagsMake, sizeof(g_sFlagsMake)); + g_iCvarMake = ReadFlagString(g_sFlagsMake); + g_hCvarMenu.GetString(g_sFlagsMenu, sizeof(g_sFlagsMenu)); + g_iCvarMenu = ReadFlagString(g_sFlagsMenu); + g_bCvarBots = g_hCvarBots.BoolValue; + g_fCvarChange = g_hCvarChange.FloatValue; + g_fCvarDetect = g_hCvarDetect.FloatValue; + g_iCvarOpaq = g_hCvarOpaq.IntValue; + g_iCvarRand = g_hCvarRand.IntValue; + g_iCvarSave = g_hCvarSave.IntValue; + g_iCvarThird = g_hCvarThird.IntValue; + g_bCvarWall = g_hCvarWall.BoolValue; +} + +void IsAllowed() +{ + bool bCvarAllow = g_hCvarAllow.BoolValue; + bool bAllowMode = IsAllowedGameMode(); + GetCvars(); + + if( g_bCvarAllow == false && bCvarAllow == true && bAllowMode == true && g_bValidMap == true ) + { + g_bCvarAllow = true; + + if( g_iCvarThird ) + HookViewEvents(); + HookEvents(); + SpectatorHatHooks(); + + for( int i = 1; i <= MaxClients; i++ ) + { + g_bHatView[i] = false; + g_iSelected[i] = GetRandomInt(0, g_iCount -1); + } + + if( g_iCvarRand || g_iCvarSave ) + { + int clientID; + + for( int i = 1; i <= MaxClients; i++ ) + { + if( IsClientInGame(i) && GetClientTeam(i) == 2 ) + { + clientID = GetClientUserId(i); + + if( g_iCvarSave && !IsFakeClient(i) ) + { + OnClientCookiesCached(i); + CreateTimer(0.3, TimerDelayCreate, clientID); + } + else if( g_iCvarRand ) + { + CreateTimer(0.3, TimerDelayCreate, clientID); + } + } + } + } + + // if( g_bLeft4Dead2 && g_fCvarDetect ) + if( g_fCvarDetect ) + { + delete g_hTimerDetect; + g_hTimerDetect = CreateTimer(g_fCvarDetect, TimerDetect, _, TIMER_REPEAT); + } + } + + else if( g_bCvarAllow == true && (bCvarAllow == false || bAllowMode == false || g_bValidMap == false) ) + { + g_bCvarAllow = false; + + UnhookViewEvents(); + UnhookEvents(); + + for( int i = 1; i <= MaxClients; i++ ) + { + RemoveHat(i); + + if( IsValidEntRef(g_iHatIndex[i]) ) + { + for( int x = 1; x <= MaxClients; x++ ) + { + if( IsClientInGame(x) ) + { + SDKUnhook(g_iHatIndex[i], SDKHook_SetTransmit, Hook_SetSpecTransmit); + } + } + } + } + } +} + +int g_iCurrentMode; +bool IsAllowedGameMode() +{ + if( g_hCvarMPGameMode == null ) + return false; + + int iCvarModesTog = g_hCvarModesTog.IntValue; + if( iCvarModesTog != 0 ) + { + if( g_bMapStarted == false ) + return false; + + g_iCurrentMode = 0; + + int entity = CreateEntityByName("info_gamemode"); + if( IsValidEntity(entity) ) + { + DispatchSpawn(entity); + HookSingleEntityOutput(entity, "OnCoop", OnGamemode, true); + HookSingleEntityOutput(entity, "OnSurvival", OnGamemode, true); + HookSingleEntityOutput(entity, "OnVersus", OnGamemode, true); + HookSingleEntityOutput(entity, "OnScavenge", OnGamemode, true); + ActivateEntity(entity); + AcceptEntityInput(entity, "PostSpawnActivate"); + if( IsValidEntity(entity) ) // Because sometimes "PostSpawnActivate" seems to kill the ent. + RemoveEdict(entity); // Because multiple plugins creating at once, avoid too many duplicate ents in the same frame + } + + if( g_iCurrentMode == 0 ) + return false; + + if( !(iCvarModesTog & g_iCurrentMode) ) + return false; + } + + char sGameModes[64], sGameMode[64]; + g_hCvarMPGameMode.GetString(sGameMode, sizeof(sGameMode)); + Format(sGameMode, sizeof(sGameMode), ",%s,", sGameMode); + + g_hCvarModes.GetString(sGameModes, sizeof(sGameModes)); + if( sGameModes[0] ) + { + Format(sGameModes, sizeof(sGameModes), ",%s,", sGameModes); + if( StrContains(sGameModes, sGameMode, false) == -1 ) + return false; + } + + g_hCvarModesOff.GetString(sGameModes, sizeof(sGameModes)); + if( sGameModes[0] ) + { + Format(sGameModes, sizeof(sGameModes), ",%s,", sGameModes); + if( StrContains(sGameModes, sGameMode, false) != -1 ) + return false; + } + + return true; +} + +void OnGamemode(const char[] output, int caller, int activator, float delay) +{ + if( strcmp(output, "OnCoop") == 0 ) + g_iCurrentMode = 1; + else if( strcmp(output, "OnSurvival") == 0 ) + g_iCurrentMode = 2; + else if( strcmp(output, "OnVersus") == 0 ) + g_iCurrentMode = 4; + else if( strcmp(output, "OnScavenge") == 0 ) + g_iCurrentMode = 8; +} + + + +// ==================================================================================================== +// OTHER BITS +// ==================================================================================================== +public void OnMapStart() +{ + g_bMapStarted = true; + g_bValidMap = true; + + char sCvar[512]; + g_hCvarPrecache.GetString(sCvar, sizeof(sCvar)); + + if( sCvar[0] != '\0' ) + { + char sMap[64]; + GetCurrentMap(sMap, sizeof(sMap)); + + Format(sMap, sizeof(sMap), ",%s,", sMap); + Format(sCvar, sizeof(sCvar), ",%s,", sCvar); + + if( StrContains(sCvar, sMap, false) != -1 ) + g_bValidMap = false; + } + + if( g_bValidMap ) + { + for( int i = 0; i < g_iCount; i++ ) + { + PrecacheModel(g_sModels[i]); + } + + // Hackish precache since L4D2 does not cache models properly (client side?) any more since recent updates + if( g_bLeft4Dead2 ) + { + RequestFrame(OnFramePrecache); + } + } +} + +void OnFramePrecache() +{ + int entity; + for( int i = 0; i < g_iCount; i++ ) + { + entity = CreateEntityByName("prop_dynamic"); + SetEntityModel(entity, g_sModels[i]); + DispatchSpawn(entity); + RemoveEdict(entity); + } +} + +public void OnMapEnd() +{ + g_bMapStarted = false; +} + +public void OnClientPutInServer(int client) +{ + g_iMenuType[client] = 0; + g_bHatAll[client] = true; + g_bHatViewTP[client] = true; + g_bHatView[client] = false; +} + +public void OnClientAuthorized(int client, const char[] sSteamID) +{ + if( g_bBlocked[client] ) + { + if( IsFakeClient(client) ) + { + g_bBlocked[client] = false; + } + else if( strcmp(sSteamID, g_sSteamID[client]) ) + { + strcopy(g_sSteamID[client], sizeof(g_sSteamID[]), sSteamID); + g_bBlocked[client] = false; + } + } +} + +public void OnClientPostAdminCheck(int client) +{ + CookieAuthTest(client); +} + +public void OnClientCookiesCached(int client) +{ + if( g_bCvarAllow && g_iCvarSave && !IsFakeClient(client) ) + { + char sCookie[4]; + + GetClientCookie(client, g_hCookie_All, sCookie, sizeof(sCookie)); + if( sCookie[0] != 0 ) + { + g_bHatAll[client] = StringToInt(sCookie) == 1; + } + + ////////////////////////////////// + // Updated by pan0s + char s1On[2], s3On[2]; + GetClientCookie(client, g_hCookie_FirstView, s1On, sizeof(s1On)); + if( s1On[0] != 0 ) + { + g_bHatView[client] = StringToInt(s1On) == 1; + } + + GetClientCookie(client, g_hCookie_ThirdView, s3On, sizeof(s3On)); + if( s3On[0] != 0 ) + { + g_bHatViewTP[client] = StringToInt(s3On) == 1; + } + ////////////////////////////////// + + // Get client cookies, set type if available or default. + GetClientCookie(client, g_hCookie_Hat, sCookie, sizeof(sCookie)); + + if( sCookie[0] == 0 ) + { + g_iType[client] = 0; + } + else + { + int type = StringToInt(sCookie); + g_iType[client] = type; + } + + CookieAuthTest(client); + } +} + +void CookieAuthTest(int client) +{ + // Check if clients allowed to use hats otherwise delete cookie/hat + if( g_iCvarMake && g_bCookieAuth[client] && !IsFakeClient(client) ) + { + int flags = GetUserFlagBits(client); + + if( !(flags & ADMFLAG_ROOT) && !(flags & g_iCvarMake) ) + { + g_iType[client] = 0; + RemoveHat(client); + SetClientCookie(client, g_hCookie_Hat, "0"); + } + } else { + g_bCookieAuth[client] = true; + } +} + +public void OnClientDisconnect(int client) +{ + g_bExternalProp[client] = false; + g_bIsThirdPerson[client] = false; + g_bExternalCvar[client] = false; + g_bExternalChange[client] = false; + g_bCookieAuth[client] = false; + delete g_hTimerDelay[client]; + delete g_hTimerView[client]; +} + +KeyValues OpenConfig() +{ + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), CONFIG_SPAWNS); + if( !FileExists(sPath) ) + SetFailState("Cannot find the file: \"%s\"", CONFIG_SPAWNS); + + KeyValues hFile = new KeyValues("models"); + if( !hFile.ImportFromFile(sPath) ) + { + delete hFile; + SetFailState("Cannot load the file: \"%s\"", CONFIG_SPAWNS); + } + return hFile; +} + +void SaveConfig(KeyValues hFile) +{ + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), CONFIG_SPAWNS); + hFile.Rewind(); + hFile.ExportToFile(sPath); +} + +void GetHatName(char sTemp[64], int index) +{ + strcopy(sTemp, sizeof(sTemp), g_sModels[index]); + ReplaceString(sTemp, sizeof(sTemp), "_", " "); + int pos = FindCharInString(sTemp, '/', true) + 1; + int len = strlen(sTemp) - pos - 3; + strcopy(sTemp, len, sTemp[pos]); +} + +bool HatsValidClient(int client) +{ + if( client && IsClientInGame(client) && GetClientTeam(client) == 2 && IsPlayerAlive(client) ) + return true; + return false; +} + +void SetReadyUpPlugin(int client, bool show) +{ + // Readyup plugin, show or hide panel + if( client > 0 && g_hPluginReadyUp && g_hPluginReadyUp.BoolValue && HatsValidClient(client) ) + { + ToggleReadyPanel(show, client); + } +} + + + + +// ==================================================================================================== +// CVAR CHANGES +// ==================================================================================================== +void CvarChangeOpac(Handle convar, const char[] oldValue, const char[] newValue) +{ + g_iCvarOpaq = g_hCvarOpaq.IntValue; + + if( g_bCvarAllow ) + { + int entity; + for( int i = 1; i <= MaxClients; i++ ) + { + entity = g_iHatIndex[i]; + if( HatsValidClient(i) && IsValidEntRef(entity) ) + { + SetEntityRenderMode(entity, RENDER_TRANSCOLOR); + SetEntityRenderColor(entity, 255, 255, 255, g_iCvarOpaq); + } + } + } +} + +void CvarChangeThird(Handle convar, const char[] oldValue, const char[] newValue) +{ + g_iCvarThird = g_hCvarThird.IntValue; + + if( g_bCvarAllow ) + { + if( g_iCvarThird ) + HookViewEvents(); + else + UnhookViewEvents(); + } +} + + + +// ==================================================================================================== +// EVENTS +// ==================================================================================================== +void HookEvents() +{ + HookEvent("round_start", Event_Start); + HookEvent("round_end", Event_RoundEnd); + HookEvent("player_death", Event_PlayerDeath); + HookEvent("player_spawn", Event_PlayerSpawn); + HookEvent("player_team", Event_PlayerTeam); +} + +void UnhookEvents() +{ + UnhookEvent("round_start", Event_Start); + UnhookEvent("round_end", Event_RoundEnd); + UnhookEvent("player_death", Event_PlayerDeath); + UnhookEvent("player_spawn", Event_PlayerSpawn); + UnhookEvent("player_team", Event_PlayerTeam); +} + +void HookViewEvents() +{ + if( g_bViewHooked == false ) + { + g_bViewHooked = true; + + HookEvent("revive_success", Event_First2); + HookEvent("player_ledge_grab", Event_Third1); + HookEvent("lunge_pounce", Event_Third2); + HookEvent("pounce_end", Event_FirstDelay); + HookEvent("tongue_grab", Event_Third2); + HookEvent("tongue_release", Event_First1); + + if( g_bLeft4Dead2 ) + { + HookEvent("upgrade_pack_begin", Event_Third1); + HookEvent("upgrade_pack_used", Event_First3); + HookEvent("charger_pummel_start", Event_Third2); + HookEvent("charger_carry_start", Event_Third2); + HookEvent("charger_carry_end", Event_First1); + HookEvent("charger_pummel_end", Event_FirstDelay); + } + } +} + +void UnhookViewEvents() +{ + if( g_bViewHooked == false ) + { + g_bViewHooked = true; + + UnhookEvent("revive_success", Event_First2); + UnhookEvent("player_ledge_grab", Event_Third1); + UnhookEvent("lunge_pounce", Event_Third2); + UnhookEvent("pounce_end", Event_FirstDelay); + UnhookEvent("tongue_grab", Event_Third2); + UnhookEvent("tongue_release", Event_First1); + + if( g_bLeft4Dead2 ) + { + UnhookEvent("upgrade_pack_begin", Event_Third1); + UnhookEvent("upgrade_pack_used", Event_First3); + UnhookEvent("charger_pummel_start", Event_Third2); + UnhookEvent("charger_carry_start", Event_Third2); + UnhookEvent("charger_carry_end", Event_First1); + UnhookEvent("charger_pummel_end", Event_FirstDelay); + } + } +} + +void Event_Start(Event event, const char[] name, bool dontBroadcast) +{ + if( g_iCvarRand == 1 ) + CreateTimer(0.5, TimerRand, _, TIMER_FLAG_NO_MAPCHANGE); + + // if( g_bLeft4Dead2 && g_fCvarDetect ) + if( g_fCvarDetect ) + { + delete g_hTimerDetect; + g_hTimerDetect = CreateTimer(g_fCvarDetect, TimerDetect, _, TIMER_REPEAT); + } +} + +Action TimerRand(Handle timer) +{ + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) && g_iType[i] != -1 ) + { + CreateHat(i, g_iType[i] ? g_iType[i] - 1 : -1); + } + } + + return Plugin_Continue; +} + +void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) +{ + for( int i = 1; i <= MaxClients; i++ ) + RemoveHat(i); +} + +void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(event.GetInt("userid")); + if( !client || !IsClientInGame(client) || GetClientTeam(client) != 2 ) + return; + + RemoveHat(client); + SpectatorHatHooks(); +} + +void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) +{ + if( g_iCvarRand == 2 || g_iCvarSave ) + { + int clientID = event.GetInt("userid"); + int client = GetClientOfUserId(clientID); + + if( client ) + { + RemoveHat(client); + CreateTimer(0.5, TimerDelayCreate, clientID); + } + } + + SpectatorHatHooks(); +} + +void Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast) +{ + int clientID = event.GetInt("userid"); + int client = GetClientOfUserId(clientID); + + RemoveHat(client); + SpectatorHatHooks(); + + if( g_iCvarRand ) + CreateTimer(0.1, TimerDelayCreate, clientID); +} + +Action TimerDelayCreate(Handle timer, int client) +{ + client = GetClientOfUserId(client); + + if( HatsValidClient(client) && !g_bBlocked[client] ) + { + bool fake = IsFakeClient(client); + if( !g_bCvarBots && fake ) + { + return Plugin_Continue; + } + + if( !fake && g_iCvarMake != 0 ) + { + int flags = GetUserFlagBits(client); + + if( !(flags & ADMFLAG_ROOT) && !(flags & g_iCvarMake) ) + { + return Plugin_Continue; + } + } + + if( g_iCvarRand == 2 ) + CreateHat(client, -2); + else if( g_iCvarSave && !IsFakeClient(client) ) + CreateHat(client, -3); + else if( g_iCvarRand ) + CreateHat(client, -1); + } + + return Plugin_Continue; +} + +void Event_FirstDelay(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(event.GetInt("victim")); + if( client ) + { + delete g_hTimerDelay[client]; + + if( name[0] == 'c' ) // charger_pummel_end + g_hTimerDelay[client] = CreateTimer(3.0, TimerDelayFirst, client); + else // pounce_end .. if( name[0] == 'p' ) + g_hTimerDelay[client] = CreateTimer(2.5, TimerDelayFirst, client); + } +} + +Action TimerDelayFirst(Handle timer, int client) +{ + g_hTimerDelay[client] = null; + + if( IsClientInGame(client) ) + { + EventHatView(client, false); + } + + return Plugin_Continue; +} + +void Event_First1(Event event, const char[] name, bool dontBroadcast) +{ + EventView(event.GetInt("victim"), false); +} + +void Event_First3(Event event, const char[] name, bool dontBroadcast) +{ + EventView(event.GetInt("userid"), false); +} + +void Event_First2(Event event, const char[] name, bool dontBroadcast) +{ + EventView(event.GetInt("subject"), false); +} + +void Event_Third1(Event event, const char[] name, bool dontBroadcast) +{ + EventView(event.GetInt("userid"), true); +} + +void Event_Third2(Event event, const char[] name, bool dontBroadcast) +{ + EventView(event.GetInt("victim"), true); +} + +void EventView(int client, bool bToThirdPerson) +{ + DataPack dPack = new DataPack(); + dPack.WriteCell(client); + dPack.WriteCell(bToThirdPerson); + RequestFrame(OnFrameEvent, dPack); +} + +void OnFrameEvent(DataPack dPack) +{ + dPack.Reset(); + int client = dPack.ReadCell(); + bool bToThirdPerson = dPack.ReadCell(); + delete dPack; + + client = GetClientOfUserId(client); + + if( client && IsClientInGame(client) ) + { + EventHatView(client, bToThirdPerson); + } +} + +void EventHatView(int client, bool bToThirdPerson) +{ + if( HatsValidClient(client) ) + { + if( bToThirdPerson ) delete g_hTimerDelay[client]; + + SetHatView(client, bToThirdPerson); + } +} + +// Show hat when thirdperson view +Action TimerDetect(Handle timer) +{ + if( g_bCvarAllow == false ) + { + g_hTimerDetect = null; + return Plugin_Stop; + } + + int target; + bool pass; + + for( int i = 1; i <= MaxClients; i++ ) + { + if( g_bExternalCvar[i] == false && g_iHatIndex[i] && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) ) + { + pass = false; + + if( g_bLeft4Dead2 ) + { + if( + GetEntPropFloat(i, Prop_Send, "m_TimeForceExternalView") > GetGameTime() || + (GetEntPropEnt(i, Prop_Send, "m_useActionTarget") != -1 && GetEntPropEnt(i, Prop_Send, "m_useActionOwner") == i) + ) + { + pass = true; + } + } + else + { + target = GetEntPropEnt(i, Prop_Send, "m_healTarget"); + if( target > 0 && target != i ) + { + pass = true; + } + } + + if( !pass ) + { + if( + GetEntPropEnt(i, Prop_Send, "m_hViewEntity") != -1 || + GetEntPropEnt(i, Prop_Send, "m_reviveTarget") != -1 || + GetEntPropFloat(i, Prop_Send, "m_staggerTimer", 1) > GetGameTime() + ) + { + pass = true; + } + } + + if( pass ) + { + // g_bIsThirdPerson[i] = true; + + if( g_bExternalProp[i] == false ) + { + g_bExternalProp[i] = true; + + if( g_bHatViewTP[i] ) + { + SetHatView(i, true); + } else { + SetHatView(i, false); + } + } + } + else + { + // g_bIsThirdPerson[i] = false; + + if( g_bExternalProp[i] == true ) + { + g_bExternalProp[i] = false; + + if( !g_bHatView[i] ) + { + SetHatView(i, false); + } + else + { + SetHatView(i, true); + } + } + } + } + } + + return Plugin_Continue; +} + +public void TP_OnThirdPersonChanged(int client, bool bIsThirdPerson) +{ + g_bIsThirdPerson[client] = bIsThirdPerson; + + if( g_fCvarDetect ) + { + // if( bIsThirdPerson && g_bExternalCvar[client] ) + // { + // SetHatView(client, false); + // } + // else if( bIsThirdPerson && !g_bExternalCvar[client] ) + if( bIsThirdPerson && !g_bExternalCvar[client] ) + { + g_bExternalCvar[client] = true; + if( g_bHatViewTP[client] ) SetHatView(client, true); + else SetHatView(client, false); + } + else if( !bIsThirdPerson && g_bExternalCvar[client] ) + { + g_bExternalCvar[client] = false; + SetHatView(client, false); + } + } +} + +void SetHatView(int client, bool bShowHat) +{ + if( bShowHat && !g_bExternalState[client] ) + { + // PrintToChatAll("HatStates On: %d %d %d %d %d %d %d", bShowHat, g_bExternalState[client], g_bExternalChange[client], g_bExternalProp[client], g_bHatView[client], g_bIsThirdPerson[client], g_bHatViewTP[client]); + g_bExternalState[client] = true; + + int entity = g_iHatIndex[client]; + if( entity && (entity = EntRefToEntIndex(entity)) != INVALID_ENT_REFERENCE ) + SDKUnhook(entity, SDKHook_SetTransmit, Hook_SetTransmit); + } + else if( !bShowHat && g_bExternalState[client] && !g_bExternalChange[client] && !g_bExternalProp[client] && ((!g_bHatView[client] && !g_bIsThirdPerson[client]) || (!g_bHatViewTP[client] && g_bIsThirdPerson[client])) ) + { + // Prevent hiding the hat if events are currently triggered to show: + if( + GetEntProp(client, Prop_Send, "m_isHangingFromLedge") == 1 || + GetEntPropEnt(client, Prop_Send, "m_reviveTarget") != -1 || + GetEntPropEnt(client, Prop_Send, "m_pounceAttacker") != -1 || + GetEntPropEnt(client, Prop_Send, "m_hViewEntity") != -1 || + ( + g_bLeft4Dead2 && + (GetEntPropEnt(client, Prop_Send, "m_carryAttacker") != -1 || GetEntPropEnt(client, Prop_Send, "m_pummelAttacker") != -1) + ) + ) + { + return; + } + + // PrintToChatAll("HatStates Off: %d %d %d %d %d %d %d", bShowHat, g_bExternalState[client], g_bExternalChange[client], g_bExternalProp[client], g_bHatView[client], g_bIsThirdPerson[client], g_bHatViewTP[client]); + g_bExternalState[client] = false; + + int entity = g_iHatIndex[client]; + if( entity && (entity = EntRefToEntIndex(entity)) != INVALID_ENT_REFERENCE ) + SDKHook(entity, SDKHook_SetTransmit, Hook_SetTransmit); + } +} + + + +// ==================================================================================================== +// BLOCK HATS - WHEN SPECTATING IN 1ST PERSON VIEW +// ==================================================================================================== +// Loop through hats, find valid ones, loop through for each client and add transmit hook for spectators +// Could be better instead of unhooking and hooking everyone each time, but quick and dirty addition... +void SpectatorHatHooks() +{ + for( int index = 1; index <= MaxClients; index++ ) + { + if( IsValidEntRef(g_iHatIndex[index]) ) + { + for( int i = 1; i <= MaxClients; i++ ) + { + if( IsClientInGame(i) ) + { + SDKUnhook(g_iHatIndex[index], SDKHook_SetTransmit, Hook_SetSpecTransmit); + + if( !IsPlayerAlive(i) ) + { + // Must hook 1 frame later because SDKUnhook first and then SDKHook doesn't work, it won't be hooked for some reason. + DataPack dPack = new DataPack(); + dPack.WriteCell(GetClientUserId(i)); + dPack.WriteCell(index); + RequestFrame(OnFrameHooks, dPack); + } + } + } + } + } +} + +void OnFrameHooks(DataPack dPack) +{ + dPack.Reset(); + + int client = dPack.ReadCell(); + client = GetClientOfUserId(client); + + if( client && IsClientInGame(client) && !IsPlayerAlive(client) ) + { + int index = dPack.ReadCell(); + int entity = EntRefToEntIndex(g_iHatIndex[index]); + if( entity != INVALID_ENT_REFERENCE ) + SDKHook(entity, SDKHook_SetTransmit, Hook_SetSpecTransmit); + } + + delete dPack; +} + +Action Hook_SetSpecTransmit(int entity, int client) +{ + if( !g_bHatAll[client] ) + { + return Plugin_Handled; + } + + if( !IsPlayerAlive(client) && GetEntProp(client, Prop_Send, "m_iObserverMode") == 4 ) + { + int target = GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); + if( target > 0 && target <= MaxClients && g_iHatIndex[target] == EntIndexToEntRef(entity) ) + { + return Plugin_Handled; + } + } + return Plugin_Continue; +} + + + +// ==================================================================================================== +// COMMANDS +// ==================================================================================================== +// sm_hats +// ==================================================================================================== +// Updated by pan0s +Action CmdHatMain(int client, int args) +{ + if( !g_bCvarAllow || !HatsValidClient(client) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return Plugin_Handled; + } + + if( g_iCvarMenu != 0 ) + { + int flags = GetUserFlagBits(client); + + if( !(flags & ADMFLAG_ROOT) && !(flags & g_iCvarMenu) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "No Access", client); + return Plugin_Handled; + } + } + + SetReadyUpPlugin(client, false); + + g_iMenuType[client] = 0; + + Menu menu = new Menu(HandleCmdHatMain); + menu.SetTitle("%T", "HAT_MAIN", client); + + char option [64]; + char optionName [10]; + bool bEnabled[4]; + bEnabled[0] = !g_bHatOff[client]; + bEnabled[1] = g_bHatView[client]; + bEnabled[2] = g_bHatViewTP[client]; + bEnabled[3] = g_bHatAll[client]; + + char options[][] = {"HAT_MENU", "HAT_WORE", "HAT_VIEWABLE", "HAT_VIEWABLE_TP", "HAT_VISIBILITY"}; + + Format(option, sizeof(option), "%T", options[0], client); + menu.AddItem("option0", option); + + for( int i=0; i < sizeof(bEnabled); i++ ) + { + Format(option, sizeof(option), "%T: %T", options[i+1], client, bEnabled[i] ? "HAT_ENABLED" : "HAT_DISABLED", client); + Format(optionName, sizeof(optionName),"option%d", i); + menu.AddItem(optionName, option); + } + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); + + return Plugin_Handled; +} + +// Handles callbacks from a client using the director commands menu. +int HandleCmdHatMain(Handle menu, MenuAction action, int client, int itemNum) +{ + if( action == MenuAction_Select ) + { + switch (itemNum) + { + case 0: + { + CmdHat(client, 0); + return 0; + } + case 1: CmdHatOff(client, 0); + case 2: CmdHatShow(client, 0); + case 3: FakeClientCommand(client, "sm_hatshow tp"); + case 4: CmdHatsToggle(client, 0); + } + + CmdHatMain(client, 0); + } + else if( action == MenuAction_End ) + { + delete menu; + } + else if( action == MenuAction_Cancel ) + { + if( client == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + + return 0; +} + +// ==================================================================================================== +// sm_hat +// ==================================================================================================== +Action CmdHat(int client, int args) +{ + if( !g_bCvarAllow || !HatsValidClient(client) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return Plugin_Handled; + } + + if( g_iCvarMenu != 0 ) + { + int flags = GetUserFlagBits(client); + + if( !(flags & ADMFLAG_ROOT) && !(flags & g_iCvarMenu) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "No Access", client); + return Plugin_Handled; + } + } + + g_iMenuType[client] = 0; + g_iTarget[client] = 0; + + if( args == 1 ) + { + char sTemp[64]; + GetCmdArg(1, sTemp, sizeof(sTemp)); + + int len = strlen(sTemp); + if( len < 4 && IsCharNumeric(sTemp[0]) && (len == 1 || IsCharNumeric(sTemp[1])) && (len == 2 || IsCharNumeric(sTemp[2])) ) + { + int index = StringToInt(sTemp); + if( index < 0 || index >= (g_iCount + 1) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_No_Index", client, index, g_iCount); + } + else + { + RemoveHat(client); + + if( index == 0 ) + { + if( g_iCvarSave && !IsFakeClient(client) ) + { + SetClientCookie(client, g_hCookie_Hat, "-1"); + g_iType[client] = -1; + } + + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Off", client); + } + else if( CreateHat(client, index - 1) ) + { + ExternalView(client); + } + } + } + else if( strncmp(sTemp, "rand", 4, false) == 0 ) + { + RemoveHat(client); + + if( CreateHat(client, GetRandomInt(1, g_iCount) - 1) ) + { + ExternalView(client); + return Plugin_Handled; + } + } + else + { + ReplaceString(sTemp, sizeof(sTemp), " ", "_"); + + for( int i = 0; i < g_iCount; i++ ) + { + if( StrContains(g_sModels[i], sTemp) != -1 || StrContains(g_sNames[i], sTemp) != -1 ) + { + RemoveHat(client); + + if( CreateHat(client, i) ) + { + ExternalView(client); + } + return Plugin_Handled; + } + } + + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Not_Found", client, sTemp); + } + } + else + { + SetReadyUpPlugin(client, false); + + ShowMenu(client); + } + + return Plugin_Handled; +} + +int HatMenuHandler(Menu menu, MenuAction action, int client, int index) +{ + if( action == MenuAction_End && client != 0 ) + { + delete menu; + } + else if( action == MenuAction_Select ) + { + int target = g_iTarget[client]; + g_bHatOff[client] = false; + + if( target ) + { + target = GetClientOfUserId(target); + if( HatsValidClient(target) ) + { + char name[MAX_NAME_LENGTH]; + GetClientName(target, name, sizeof(name)); + + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Changed", client, name); + RemoveHat(target); + + if( index != 0 && CreateHat(target, index - 1) ) + { + ExternalView(target); + } + + ShowMenu(client); + } + else + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Invalid", client); + + ShowMenu(client); + } + + return 0; + } + else + { + RemoveHat(client); + + if( index == 0 ) + { + if( g_iCvarSave && !IsFakeClient(client) ) + { + SetClientCookie(client, g_hCookie_Hat, "-1"); + g_iType[client] = -1; + } + + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Off", client); + } + else if( CreateHat(client, index - 1) ) + { + ExternalView(client); + } + } + + int menupos = menu.Selection; + menu.DisplayAt(client, menupos, MENU_TIME_FOREVER); + } + else if( action == MenuAction_Cancel ) + { + if( index == MenuCancel_ExitBack ) + { + if( g_iMenuType[client] == 0 ) + { + CmdHatMain(client, 0); + } + else + { + CmdHatTarget(client, 0); + } + } + else if( index == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + + return 0; +} + +void ShowMenu(int client) +{ + SetReadyUpPlugin(client, false); + + if( g_bTranslation == false ) + { + g_hMenu.Display(client, MENU_TIME_FOREVER); + } + else + { + static char sMsg[128]; + Menu hTemp = new Menu(HatMenuHandler); + hTemp.SetTitle("%T", "Hat_Menu_Title", client); + FormatEx(sMsg, sizeof(sMsg), "%T", "HAT_DISABLED", client); + hTemp.AddItem("HAT_DISABLED", sMsg); + + for( int i = 0; i < g_iCount; i++ ) + { + FormatEx(sMsg, sizeof(sMsg), "%s", g_sModels[i]); + int lang = GetClientLanguage(client); + + if( IsTranslatedForLanguage(sMsg, lang) == true ) + { + Format(sMsg, sizeof(sMsg), "%T", sMsg, client); + hTemp.AddItem(g_sModels[i], sMsg); + } else { + FormatEx(sMsg, sizeof(sMsg), "Hat %d", i + 1); + if( IsTranslatedForLanguage(sMsg, lang) == true ) + { + Format(sMsg, sizeof(sMsg), "%T", sMsg, client); + hTemp.AddItem(g_sModels[i], sMsg); + } else { + hTemp.AddItem(g_sModels[i], g_sNames[i]); + } + } + } + + hTemp.ExitBackButton = true; + hTemp.Display(client, MENU_TIME_FOREVER); + + g_hMenus[client] = hTemp; + } +} + +// ==================================================================================================== +// sm_hatoff +// ==================================================================================================== +Action CmdHatOff(int client, int args) +{ + if( !g_bCvarAllow || g_bBlocked[client] ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return Plugin_Handled; + } + + g_bHatOff[client] = !g_bHatOff[client]; + + if( g_bHatOff[client] ) + RemoveHat(client); + + char sTemp[64]; + FormatEx(sTemp, sizeof(sTemp), "%T", g_bHatOff[client] ? "Hat_Off" : "Hat_On", client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Ability", client, sTemp); + + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatshow +// ==================================================================================================== +Action CmdHatShowOn(int client, int args) +{ + g_bHatView[client] = false; + CmdHatShow(client, args); + return Plugin_Handled; +} + +Action CmdHatShowOff(int client, int args) +{ + g_bHatView[client] = true; + CmdHatShow(client, args); + return Plugin_Handled; +} + +Action CmdHatShow(int client, int args) +{ + if( !g_bCvarAllow || g_bBlocked[client] ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return Plugin_Handled; + } + + int entity = g_iHatIndex[client]; + if( entity == 0 || (entity = EntRefToEntIndex(entity)) == INVALID_ENT_REFERENCE ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Missing", client); + return Plugin_Handled; + } + + /////////////////////////////////////////// + // Updated by pan0s + if( args == 1 ) + { + char sVar[3]; + + GetCmdArgString(sVar, sizeof(sVar)); + if( strcmp(sVar, "tp", false) == 0 ) + { + g_bHatViewTP[client] = !g_bHatViewTP[client]; + + if( g_bIsThirdPerson[client] ) + { + if( !g_bHatViewTP[client] ) + SetHatView(client, false); + else + SetHatView(client, true); + } + + IntToString(g_bHatViewTP[client], sVar, sizeof(sVar)); + SetClientCookie(client, g_hCookie_ThirdView, sVar); + + char sTemp[64]; + Format(sTemp, sizeof(sTemp), "%T", g_bHatViewTP[client] ? "Hat_On" : "Hat_Off", client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_ViewTP", client, sTemp); + + return Plugin_Handled; + } + } + /////////////////////////////////////////// + + g_bHatView[client] = !g_bHatView[client]; + + if( !g_bHatView[client] && (!g_bIsThirdPerson[client] || !g_bHatViewTP[client]) ) + SetHatView(client, false); + else if( g_bHatView[client] && (!g_bIsThirdPerson[client] || g_bHatViewTP[client]) ) + SetHatView(client, true); + + char sTemp[64]; + IntToString(g_bHatView[client], sTemp, sizeof(sTemp)); + SetClientCookie(client, g_hCookie_FirstView, sTemp); + + FormatEx(sTemp, sizeof(sTemp), "%T", g_bHatView[client] ? "Hat_On" : "Hat_Off", client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_View", client, sTemp); + + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatall +// ==================================================================================================== +Action CmdHatsToggle(int client, int args) +{ + if( !g_bCvarAllow ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return Plugin_Handled; + } + + g_bHatAll[client] = !g_bHatAll[client]; + + char sTemp[64]; + FormatEx(sTemp, sizeof(sTemp), "%T", g_bHatAll[client] ? "Hat_On" : "Hat_Off", client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Visibility_Set", client, sTemp); + + // Save hat visibility + SetClientCookie(client, g_hCookie_All, g_bHatAll[client] ? "1" : "0"); + + return Plugin_Handled; +} + + + +// ==================================================================================================== +// ADMIN COMMANDS +// ==================================================================================================== +// sm_hatrand / sm_ratrandom +// ==================================================================================================== +Action CmdHatRand(int client, int args) +{ + if( g_bCvarAllow ) + { + for( int i = 1; i <= MaxClients; i++ ) + { + RemoveHat(i); + } + + int last = g_iCvarRand; + g_iCvarRand = 1; + + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) ) + { + CreateHat(i, -1); + } + } + + g_iCvarRand = last; + } + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatclient +// ==================================================================================================== +Action CmdHatClient(int client, int args) +{ + if( args == 0 ) + { + ReplyToCommand(client, "Usage: sm_hatclient <#userid|name> [hat name or hat index: 0-128 (MAX_HATS)]."); + return Plugin_Handled; + } + + char sArg[32], target_name[MAX_TARGET_LENGTH]; + GetCmdArg(1, sArg, sizeof(sArg)); + + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + + if( (target_count = ProcessTargetString( + sArg, + client, + target_list, + MAXPLAYERS, + COMMAND_FILTER_ALIVE, /* Only allow alive players */ + target_name, + sizeof(target_name), + tn_is_ml)) <= 0 ) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + int index = -1; + if( args == 2 ) + { + GetCmdArg(2, sArg, sizeof(sArg)); + + if( strlen(sArg) > 3 ) + { + for( int i = 0; i < g_iCount; i++ ) + { + if( strcmp(g_sNames[i], sArg, false) == 0 ) + { + index = i; + break; + } + } + } else { + index = StringToInt(sArg); + } + } + else + { + index = GetRandomInt(0, g_iCount - 1); + } + + for( int i = 0; i < target_count; i++ ) + { + if( GetClientTeam(target_list[i]) == 2 ) + { + RemoveHat(target_list[i]); + CreateHat(target_list[i], index); + ReplyToCommand(client, "[Hat] Set '%N' to '%s'", target_list[i], g_sNames[index]); + } + } + + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatc / sm_hatoffc / sm_hatallc +// ==================================================================================================== +Action CmdHatTarget(int client, int args) +{ + if( g_bCvarAllow ) + { + g_iMenuType[client] = 1; + ShowPlayerList(client); + } + return Plugin_Handled; +} + +Action CmdHatOffTarget(int client, int args) +{ + if( g_bCvarAllow ) + { + g_iMenuType[client] = 2; + ShowPlayerList(client); + } + return Plugin_Handled; +} + +Action CmdHatAllTarget(int client, int args) +{ + if( g_bCvarAllow ) + { + g_iMenuType[client] = 3; + ShowPlayerList(client); + } + return Plugin_Handled; +} + +void ShowPlayerList(int client) +{ + if( client && IsClientInGame(client) ) + { + SetReadyUpPlugin(client, false); + + char sTempA[8], sTempB[MAX_NAME_LENGTH]; + Menu menu = new Menu(PlayerListMenu); + + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) ) + { + IntToString(GetClientUserId(i), sTempA, sizeof(sTempA)); + GetClientName(i, sTempB, sizeof(sTempB)); + menu.AddItem(sTempA, sTempB); + } + } + + switch( g_iMenuType[client] ) + { + case 1: menu.SetTitle("%T", "ADMIN_CHANGE_HAT", client); + case 2: menu.SetTitle("%T", "ADMIN_DISABLE_HAT", client); + case 3: menu.SetTitle("%T", "ADMIN_VISIBILITY", client); + } + + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); + } +} + +int PlayerListMenu(Menu menu, MenuAction action, int client, int index) +{ + if( action == MenuAction_End ) + { + delete menu; + } + else if( action == MenuAction_Cancel ) + { + if( index == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + else if( action == MenuAction_Select ) + { + char sTemp[64]; + menu.GetItem(index, sTemp, sizeof(sTemp)); + int target = StringToInt(sTemp); + target = GetClientOfUserId(target); + + switch( g_iMenuType[client] ) + { + case 1: + { + if( HatsValidClient(target) ) + { + g_iTarget[client] = GetClientUserId(target); + + ShowMenu(client); + } + } + case 2: + { + g_bBlocked[target] = !g_bBlocked[target]; + + if( g_bBlocked[target] == false ) + { + if( HatsValidClient(target) ) + { + RemoveHat(target); + CreateHat(target); + + char name[MAX_NAME_LENGTH]; + GetClientName(target, name, sizeof(name)); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Unblocked", client, name); + } + } + else + { + if( HatsValidClient(target) ) + { + char name[MAX_NAME_LENGTH]; + GetClientName(target, name, sizeof(name)); + GetClientAuthId(target, AuthId_Steam2, g_sSteamID[target], sizeof(g_sSteamID[])); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Blocked", client, name); + RemoveHat(target); + } + } + + ShowPlayerList(client); + } + case 3: + { + g_bHatAll[target] = !g_bHatAll[target]; + + if( HatsValidClient(target) ) + { + char name[MAX_NAME_LENGTH]; + GetClientName(target, name, sizeof(name)); + FormatEx(sTemp, sizeof(sTemp), "%T", g_bHatAll[target] ? "Hat_On" : "Hat_Off", client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_ViewSet", client, name, sTemp); + } + + ShowPlayerList(client); + } + } + } + + return 0; +} + +// ==================================================================================================== +// sm_hatadd +// ==================================================================================================== +Action CmdHatAdd(int client, int args) +{ + if( !g_bCvarAllow ) + return Plugin_Handled; + + if( args == 1 ) + { + if( g_iCount < MAX_HATS ) + { + char sTemp[64], sKey[4]; + GetCmdArg(1, sTemp, sizeof(sTemp)); + + if( FileExists(sTemp, true) ) + { + strcopy(g_sModels[g_iCount], sizeof(g_sModels[]), sTemp); + g_vAng[g_iCount] = view_as({ 0.0, 0.0, 0.0 }); + g_vPos[g_iCount] = view_as({ 0.0, 0.0, 0.0 }); + g_fSize[g_iCount] = 1.0; + + KeyValues hFile = OpenConfig(); + IntToString(g_iCount+1, sKey, sizeof(sKey)); + hFile.JumpToKey(sKey, true); + hFile.SetString("mod", sTemp); + SaveConfig(hFile); + delete hFile; + g_iCount++; + ReplyToCommand(client, "%TAdded hat '\05%s\x03' %d/%d", "HAT_SYSTEM", client, sTemp, g_iCount, MAX_HATS); + + if( g_bTranslation ) + { + ReplyToCommand(client, "%TYou must add the translation for this hat or the plugin will break.", "HAT_SYSTEM", client); + } + } + else + ReplyToCommand(client, "%TCould not find the model '\05%s'. Not adding to config.", "HAT_SYSTEM", client, sTemp); + } + else + { + ReplyToCommand(client, "%TReached maximum number of hats (%d)", "HAT_SYSTEM", client, MAX_HATS); + } + } + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatdel +// ==================================================================================================== +Action CmdHatDel(int client, int args) +{ + if( !g_bCvarAllow ) + return Plugin_Handled; + + if( args == 1 ) + { + char sTemp[64]; + int index; + bool bDeleted; + + GetCmdArg(1, sTemp, sizeof(sTemp)); + int len = strlen(sTemp); + if( len < 4 && IsCharNumeric(sTemp[0]) && (len == 1 || IsCharNumeric(sTemp[1])) && (len == 2 || IsCharNumeric(sTemp[2])) ) + { + index = StringToInt(sTemp); + if( index < 1 || index >= (g_iCount + 1) ) + { + ReplyToCommand(client, "%TCannot find the hat index %d, values between 1 and %d", "HAT_SYSTEM", client, index, g_iCount); + return Plugin_Handled; + } + index--; + strcopy(sTemp, sizeof(sTemp), g_sModels[index]); + } + else + { + index = 0; + } + + char sModel[64], sKey[4]; + KeyValues hFile = OpenConfig(); + + for( int i = index; i < MAX_HATS; i++ ) + { + IntToString(i+1, sKey, sizeof(sKey)); + if( hFile.JumpToKey(sKey) ) + { + if( bDeleted ) + { + IntToString(i, sKey, sizeof(sKey)); + hFile.SetSectionName(sKey); + + strcopy(g_sModels[i-1], sizeof(g_sModels[]), g_sModels[i]); + strcopy(g_sNames[i-1], sizeof(g_sNames[]), g_sNames[i]); + g_vAng[i-1] = g_vAng[i]; + g_vPos[i-1] = g_vPos[i]; + g_fSize[i-1] = g_fSize[i]; + } + else + { + hFile.GetString("mod", sModel, sizeof(sModel)); + if( StrContains(sModel, sTemp) != -1 ) + { + ReplyToCommand(client, "%TYou have deleted the hat '\x05%s\x03'", "HAT_SYSTEM", client, sModel); + hFile.DeleteThis(); + + g_iCount--; + bDeleted = true; + + if( g_bTranslation == false ) + { + g_hMenu.RemoveItem(i); + } + else + { + for( int x = 1; x <= MAXPLAYERS; x++ ) + { + if( g_hMenus[x] != null ) + { + g_hMenus[x].RemoveItem(i); + } + } + } + } + } + } + + hFile.Rewind(); + if( i == MAX_HATS - 1 ) + { + if( bDeleted ) + SaveConfig(hFile); + else + ReplyToCommand(client, "%TCould not delete hat, did not find model '\x05%s\x03'", "HAT_SYSTEM", client, sTemp); + } + } + delete hFile; + } + else + { + int index = g_iSelected[client]; + + TranslateHatName(client, index); + } + return Plugin_Handled; +} + +void TranslateHatName(int client, int index) +{ + if( g_bTranslation == false ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Wearing", client, g_sNames[index]); + } + else + { + static char sMsg[128]; + FormatEx(sMsg, sizeof(sMsg), "%s", g_sModels[index]); + int lang = GetClientLanguage(client); + + if( IsTranslatedForLanguage(sMsg, lang) == true ) + { + Format(sMsg, sizeof(sMsg), "%T", sMsg, client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Wearing", client, sMsg); + } else { + FormatEx(sMsg, sizeof(sMsg), "Hat %d", index + 1); + if( IsTranslatedForLanguage(sMsg, lang) == true ) + { + Format(sMsg, sizeof(sMsg), "%T", sMsg, client); + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Wearing", client, sMsg); + } else { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "Hat_Wearing", client, g_sNames[index]); + } + } + } +} + +// ==================================================================================================== +// sm_hatlist +// ==================================================================================================== +Action CmdHatList(int client, int args) +{ + for( int i = 0; i < g_iCount; i++ ) + ReplyToCommand(client, "%d) %s", i+1, g_sModels[i]); + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatload +// ==================================================================================================== +Action CmdHatLoad(int client, int args) +{ + if( g_bCvarAllow && HatsValidClient(client) ) + { + int selected = g_iSelected[client]; + PrintToChat(client, "%TLoaded hat '\x05%s\x03' on all players.", "HAT_SYSTEM", client, g_sModels[selected]); + + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) ) + { + RemoveHat(i); + CreateHat(i, selected); + } + } + } + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatsave +// ==================================================================================================== +Action CmdHatSave(int client, int args) +{ + if( g_bCvarAllow && HatsValidClient(client) ) + { + int entity = g_bCvarWall ? g_iHatWalls[client] : g_iHatIndex[client]; + if( IsValidEntRef(entity) ) + { + KeyValues hFile = OpenConfig(); + int index = g_iSelected[client]; + + char sTemp[4]; + IntToString(index+1, sTemp, sizeof(sTemp)); + if( hFile.JumpToKey(sTemp) ) + { + float vAng[3], vPos[3]; + float fSize; + + GetEntPropVector(entity, Prop_Send, "m_angRotation", vAng); + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", vPos); + hFile.SetVector("ang", vAng); + hFile.SetVector("loc", vPos); + g_vAng[index] = vAng; + g_vPos[index] = vPos; + + if( g_bLeft4Dead2 ) + { + entity = g_iHatIndex[client]; + if( IsValidEntRef(entity) ) + { + fSize = GetEntPropFloat(entity, Prop_Send, "m_flModelScale"); + if( fSize == 1.0 ) + { + if( hFile.GetFloat("size", 999.9) != 999.9 ) + hFile.DeleteKey("size"); + } + else + hFile.SetFloat("size", fSize); + + g_fSize[index] = fSize; + } + } + + SaveConfig(hFile); + PrintToChat(client, "%TSaved '\x05%s\x03' hat origin and angles.", "HAT_SYSTEM", client, g_sModels[index]); + } + else + { + PrintToChat(client, "%T\x04Warning: \x03Could not save '\x05%s\x03' hat origin and angles.", "HAT_SYSTEM", client, g_sModels[index]); + } + delete hFile; + } + } + + return Plugin_Handled; +} + +// ==================================================================================================== +// sm_hatang +// ==================================================================================================== +Action CmdAng(int client, int args) +{ + if( g_bCvarAllow ) + ShowAngMenu(client); + return Plugin_Handled; +} + +void ShowAngMenu(int client) +{ + if( !HatsValidClient(client) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return; + } + + SetReadyUpPlugin(client, false); + + Menu menu = new Menu(AngMenuHandler); + + menu.AddItem("", "X + 10.0"); + menu.AddItem("", "Y + 10.0"); + menu.AddItem("", "Z + 10.0"); + menu.AddItem("", "Reset"); + menu.AddItem("", "X - 10.0"); + menu.AddItem("", "Y - 10.0"); + menu.AddItem("", "Z - 10.0"); + + menu.SetTitle("%T", "HAT_SET_ANGLE", client); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int AngMenuHandler(Menu menu, MenuAction action, int client, int index) +{ + if( action == MenuAction_End ) + { + delete menu; + } + else if( action == MenuAction_Cancel ) + { + if( index == MenuCancel_ExitBack ) + { + ShowAngMenu(client); + } + else if( index == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + else if( action == MenuAction_Select ) + { + if( HatsValidClient(client) ) + { + ShowAngMenu(client); + + float vAng[3]; + int entity; + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) ) + { + entity = g_bCvarWall ? g_iHatWalls[i] : g_iHatIndex[i]; + if( IsValidEntRef(entity) ) + { + GetEntPropVector(entity, Prop_Send, "m_angRotation", vAng); + + switch( index ) + { + case 0: vAng[0] += 10.0; + case 1: vAng[1] += 10.0; + case 2: vAng[2] += 10.0; + case 3: vAng = view_as({0.0,0.0,0.0}); + case 4: vAng[0] -= 10.0; + case 5: vAng[1] -= 10.0; + case 6: vAng[2] -= 10.0; + } + + TeleportEntity(entity, NULL_VECTOR, vAng, NULL_VECTOR); + } + } + } + + CPrintToChat(client, "%TNew hat angles: %f %f %f", "HAT_SYSTEM", client, vAng[0], vAng[1], vAng[2]); + } + } + + return 0; +} + +// ==================================================================================================== +// sm_hatpos +// ==================================================================================================== +Action CmdPos(int client, int args) +{ + if( g_bCvarAllow ) + ShowPosMenu(client); + return Plugin_Handled; +} + +void ShowPosMenu(int client) +{ + if( !HatsValidClient(client) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return; + } + + SetReadyUpPlugin(client, false); + + Menu menu = new Menu(PosMenuHandler); + + menu.AddItem("", "X + 0.5"); + menu.AddItem("", "Y + 0.5"); + menu.AddItem("", "Z + 0.5"); + menu.AddItem("", "Reset"); + menu.AddItem("", "X - 0.5"); + menu.AddItem("", "Y - 0.5"); + menu.AddItem("", "Z - 0.5"); + + menu.SetTitle("%T", "HAT_SET_POSITION", client); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int PosMenuHandler(Menu menu, MenuAction action, int client, int index) +{ + if( action == MenuAction_End ) + { + delete menu; + } + else if( action == MenuAction_Cancel ) + { + if( index == MenuCancel_ExitBack ) + { + ShowPosMenu(client); + } + else if( index == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + else if( action == MenuAction_Select ) + { + if( HatsValidClient(client) ) + { + ShowPosMenu(client); + + float vPos[3]; + int entity; + for( int i = 1; i <= MaxClients; i++ ) + { + if( HatsValidClient(i) ) + { + entity = g_bCvarWall ? g_iHatWalls[i] : g_iHatIndex[i]; + if( IsValidEntRef(entity) ) + { + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", vPos); + + switch( index ) + { + case 0: vPos[0] += 0.5; + case 1: vPos[1] += 0.5; + case 2: vPos[2] += 0.5; + case 3: vPos = view_as({0.0,0.0,0.0}); + case 4: vPos[0] -= 0.5; + case 5: vPos[1] -= 0.5; + case 6: vPos[2] -= 0.5; + } + + TeleportEntity(entity, vPos, NULL_VECTOR, NULL_VECTOR); + } + } + } + + CPrintToChat(client, "%TNew hat origin: %f %f %f", "HAT_SYSTEM", client, vPos[0], vPos[1], vPos[2]); + } + } + + return 0; +} + +// ==================================================================================================== +// sm_hatsize +// ==================================================================================================== +Action CmdHatSize(int client, int args) +{ + if( g_bCvarAllow ) + ShowSizeMenu(client); + return Plugin_Handled; +} + +void ShowSizeMenu(int client) +{ + if( !HatsValidClient(client) ) + { + CPrintToChat(client, "%T%T", "HAT_SYSTEM", client, "HAT_NOT_RIGHT_NOW", client); + return; + } + + if( !g_bLeft4Dead2 ) + { + CPrintToChat(client, "%TCannot set hat size in L4D1.", "HAT_SYSTEM", client); + return; + } + + SetReadyUpPlugin(client, false); + + Menu menu = new Menu(SizeMenuHandler); + + menu.AddItem("", "+ 0.1"); + menu.AddItem("", "- 0.1"); + menu.AddItem("", "+ 0.5"); + menu.AddItem("", "- 0.5"); + menu.AddItem("", "+ 1.0"); + menu.AddItem("", "- 1.0"); + menu.AddItem("", "Reset"); + + menu.SetTitle("%T", "HAT_SET_SIZE", client); + menu.ExitButton = true; + menu.Display(client, MENU_TIME_FOREVER); +} + +int SizeMenuHandler(Menu menu, MenuAction action, int client, int index) +{ + if( action == MenuAction_End ) + { + delete menu; + } + else if( action == MenuAction_Cancel ) + { + if( index == MenuCancel_ExitBack ) + { + ShowSizeMenu(client); + } + else if( index == MenuCancel_Exit ) + { + SetReadyUpPlugin(client, true); + } + } + else if( action == MenuAction_Select ) + { + if( HatsValidClient(client) ) + { + ShowSizeMenu(client); + + float fSize; + int entity; + for( int i = 1; i <= MaxClients; i++ ) + { + entity = g_iHatIndex[i]; + if( IsValidEntRef(entity) ) + { + fSize = GetEntPropFloat(entity, Prop_Send, "m_flModelScale"); + + switch( index ) + { + case 0: fSize += 0.1; + case 1: fSize -= 0.1; + case 2: fSize += 0.5; + case 3: fSize -= 0.5; + case 4: fSize += 1.0; + case 5: fSize -= 1.0; + case 6: fSize = 1.0; + } + + SetEntPropFloat(entity, Prop_Send, "m_flModelScale", fSize); + } + } + + CPrintToChat(client, "%TNew hat scale: %f", "HAT_SYSTEM", client, fSize); + } + } + + return 0; +} + + + +// ==================================================================================================== +// HAT STUFF +// =================================================================================================== +void RemoveHat(int client) +{ + // Hat entity + int entity = g_iHatIndex[client]; + g_iHatIndex[client] = 0; + + if( IsValidEntRef(entity) ) + RemoveEntity(entity); + + // Hidden entity + entity = g_iHatWalls[client]; + g_iHatWalls[client] = 0; + + if( IsValidEntRef(entity) ) + RemoveEntity(entity); +} + +bool CreateHat(int client, int index = -1) +{ + if( g_bBlocked[client] || g_bHatOff[client] || IsValidEntRef(g_iHatIndex[client]) == true || HatsValidClient(client) == false ) + return false; + + if( index == -1 ) // Random hat + { + if( g_iCvarRand == 0 ) return false; + if( g_iType[client] == -1 ) return false; + + if( g_iCvarMenu != 0 ) + { + if( IsFakeClient(client) ) + return false; + + int flags = GetUserFlagBits(client); + if( !(flags & ADMFLAG_ROOT) && !(flags & g_iCvarMenu) ) + return false; + } + + index = GetRandomInt(1, g_iCount); + g_iType[client] = index; + } + else if( index == -2 ) // Previous random hat + { + if( g_iCvarRand != 2 ) return false; + + index = g_iType[client]; + if( index == -1 ) return false; + + if( index == 0 ) + { + index = GetRandomInt(1, g_iCount); + g_iType[client] = index; + } + + index--; + } + else if( index == -3 ) // Saved hats + { + index = g_iType[client]; + if( index == -1 ) return false; + + if( index == 0 ) + { + if( IsFakeClient(client) ) + { + return false; + } + else + { + if( g_iCvarRand == 0 ) return false; + + index = GetRandomInt(1, g_iCount); + g_iType[client] = index; + } + } + + index--; + } + else // Specified hat + { + g_iType[client] = index + 1; + } + + if( g_iCvarSave && !IsFakeClient(client) ) + { + char sNum[4]; + IntToString(index + 1, sNum, sizeof(sNum)); + SetClientCookie(client, g_hCookie_Hat, sNum); + + /////////////////////////////////////////// + // Updated by pan0s + char s1On[2]; + char s3On[2]; + IntToString(g_bHatView[client], s1On, sizeof(s1On)); + SetClientCookie(client, g_hCookie_FirstView, s1On); + IntToString(g_bHatViewTP[client], s3On, sizeof(s3On)); + SetClientCookie(client, g_hCookie_ThirdView, s3On); + /////////////////////////////////////////// + } + + // Fix showing glow through walls, break glow inheritance by attaching hats to info_target. + // Method by "Marttt": https://forums.alliedmods.net/showpost.php?p=2737781&postcount=21 + int target; + + if( g_bCvarWall ) + { + target = CreateEntityByName("info_target"); + DispatchSpawn(target); + } + + int entity = CreateEntityByName("prop_dynamic_override"); + if( entity != -1 ) + { + SetEntityModel(entity, g_sModels[index]); + DispatchSpawn(entity); + if( g_bLeft4Dead2 ) + { + SetEntPropFloat(entity, Prop_Send, "m_flModelScale", g_fSize[index]); + } + + if( g_bCvarWall ) + { + SetVariantString("!activator"); + AcceptEntityInput(entity, "SetParent", target); + TeleportEntity(target, g_vPos[index], NULL_VECTOR, NULL_VECTOR); + + SetVariantString("!activator"); + AcceptEntityInput(target, "SetParent", client); + SetVariantString("eyes"); + AcceptEntityInput(target, "SetParentAttachment"); + TeleportEntity(target, g_vPos[index], NULL_VECTOR, NULL_VECTOR); + + g_iHatWalls[client] = EntIndexToEntRef(target); + } else { + SetVariantString("!activator"); + AcceptEntityInput(entity, "SetParent", client); + SetVariantString("eyes"); + AcceptEntityInput(entity, "SetParentAttachment"); + TeleportEntity(entity, g_vPos[index], NULL_VECTOR, NULL_VECTOR); + } + + // Lux + AcceptEntityInput(entity, "DisableCollision"); + SetEntProp(entity, Prop_Send, "m_noGhostCollision", 1, 1); + SetEntProp(entity, Prop_Data, "m_CollisionGroup", 0x0004); + SetEntPropVector(entity, Prop_Send, "m_vecMins", view_as({0.0, 0.0, 0.0})); + SetEntPropVector(entity, Prop_Send, "m_vecMaxs", view_as({0.0, 0.0, 0.0})); + // Lux + + TeleportEntity(g_bCvarWall ? target : entity, g_vPos[index], g_vAng[index], NULL_VECTOR); + SetEntProp(entity, Prop_Data, "m_iEFlags", 0); + + if( g_iCvarOpaq ) + { + SetEntityRenderMode(entity, RENDER_TRANSCOLOR); + SetEntityRenderColor(entity, 255, 255, 255, g_iCvarOpaq); + } + + g_iSelected[client] = index; + g_iHatIndex[client] = EntIndexToEntRef(entity); + + if( !g_bHatView[client] && (!g_bIsThirdPerson[client] || !g_bHatViewTP[client]) ) + { + g_bExternalState[client] = true; + SetHatView(client, false); + } + else if( g_bHatView[client] && (!g_bIsThirdPerson[client] || g_bHatViewTP[client]) ) + { + SetHatView(client, true); + } + + TranslateHatName(client, index); + + SpectatorHatHooks(); + return true; + } + + return false; +} + +void ExternalView(int client) +{ + if( g_fCvarChange && g_bLeft4Dead2 ) + { + EventHatView(client, true); + + g_bExternalChange[client] = true; + + delete g_hTimerView[client]; + g_hTimerView[client] = CreateTimer(g_fCvarChange + (g_fCvarChange >= 2.0 ? 0.4 : 0.2), TimerEventView, GetClientUserId(client)); + + // Survivor Thirdperson plugin sets 99999.3. + if( GetEntPropFloat(client, Prop_Send, "m_TimeForceExternalView") != 99999.3 ) + SetEntPropFloat(client, Prop_Send, "m_TimeForceExternalView", GetGameTime() + g_fCvarChange); + } +} + +Action TimerEventView(Handle timer, int client) +{ + client = GetClientOfUserId(client); + if( client ) + { + g_hTimerView[client] = null; + g_bExternalChange[client] = false; + + EventHatView(client, false); + } + + return Plugin_Continue; +} + +Action Hook_SetTransmit(int entity, int client) +{ + if( !g_bHatAll[client] || EntIndexToEntRef(entity) == g_iHatIndex[client] ) + return Plugin_Handled; + return Plugin_Continue; +} + +bool IsValidEntRef(int entity) +{ + if( entity && EntRefToEntIndex(entity) != INVALID_ENT_REFERENCE ) + return true; + return false; +} + + + +// ==================================================================================================== +// COLORS.INC REPLACEMENT +// ==================================================================================================== +/* +void CPrintToChat(int client, char[] message, any ...) +{ + static char buffer[256]; + VFormat(buffer, sizeof(buffer), message, 3); + + ReplaceString(buffer, sizeof(buffer), "{DEFAULT}", "\x01", false); + ReplaceString(buffer, sizeof(buffer), "{WHITE}", "\x01", false); + ReplaceString(buffer, sizeof(buffer), "{CYAN}", "\x03", false); + ReplaceString(buffer, sizeof(buffer), "{LIGHTGREEN}", "\x03", false); + ReplaceString(buffer, sizeof(buffer), "{ORANGE}", "\x04", false); + ReplaceString(buffer, sizeof(buffer), "{GREEN}", "\x04", false); // Actually orange in L4D2, but replicating colors.inc behaviour + ReplaceString(buffer, sizeof(buffer), "{OLIVE}", "\x05", false); + + PrintToChat(client, buffer); +} +*/ + + + +/************************************************************************** + * * + * New color inc * + * Author: Ernecio (updated by pan0s) * + * Version: 1.0.1 * + * * + **************************************************************************/ +enum +{ + SERVER_INDEX = 0, + NO_INDEX = -1, + NO_PLAYER = -2, + BLUE_INDEX = 2, + RED_INDEX = 3, +} + +stock const char CTag[][] = { "{DEFAULT}", "{ORANGE}", "{CYAN}", "{RED}", "{BLUE}", "{GREEN}" }; +stock const char CTagCode[][] = { "\x01", "\x04", "\x03", "\x03", "\x03", "\x05" }; +stock const bool CTagReqSayText2[] = { false, false, true, true, true, false }; +stock const int CProfile_TeamIndex[] = { NO_INDEX, NO_INDEX, SERVER_INDEX, RED_INDEX, BLUE_INDEX, NO_INDEX }; + +/** + * @note Prints a message to a specific client in the chat area. + * @note Supports color tags. + * + * @param client Client index. + * @param sMessage Message (formatting rules). + * @return No return + * + * On error/Errors: If the client is not connected an error will be thrown. + */ +stock void CPrintToChat(int client, const char[] sMessage, any ...) +{ + if( client <= 0 || client > MaxClients ) + ThrowError( "Invalid client index %d", client); + + if( !IsClientInGame(client) ) + ThrowError( "Client %d is not in game", client); + + static char sBuffer[250]; + static char sCMessage[250]; + SetGlobalTransTarget(client); + Format(sBuffer, sizeof(sBuffer), "\x01%s", sMessage); + VFormat( sCMessage, sizeof( sCMessage ), sBuffer, 3); + + int index = CFormat(sCMessage, sizeof(sCMessage)); + if( index == NO_INDEX ) + PrintToChat(client, sCMessage); + else + CSayText2(client, index, sCMessage); +} + +/** + * @note Prints a message to all clients in the chat area. + * @note Supports color tags. + * + * @param client Client index. + * @param sMessage Message (formatting rules) + * @return No return + */ +stock void CPrintToChatAll(const char[] sMessage, any ...) +{ + static char sBuffer[250]; + + for( int i = 1; i <= MaxClients; i++ ) + { + if( IsClientInGame(i) && !IsFakeClient(i) ) + { + SetGlobalTransTarget(i); + VFormat(sBuffer, sizeof(sBuffer), sMessage, 2); + CPrintToChat(i, sBuffer); + } + } +} + +/** + * @note Replaces color tags in a string with color codes + * + * @param sMessage String. + * @param maxlength Maximum length of the string buffer. + * @return Client index that can be used for SayText2 author index + * + * On error/Errors: If there is more then one team color is used an error will be thrown. + */ +stock int CFormat(char[] sMessage, int maxlength) +{ + int iRandomPlayer = NO_INDEX; + + for( int i = 0; i < sizeof(CTagCode); i++ ) // Para otras etiquetas de color se requiere un bucle. + { + if( StrContains( sMessage, CTag[i]) == -1 ) // Si no se encuentra la etiqueta, omitir. + continue; + else if( !CTagReqSayText2[i] ) + ReplaceString(sMessage, maxlength, CTag[i], CTagCode[i]); // Si la etiqueta no necesita Saytext2 simplemente reemplazará. + else // La etiqueta necesita Saytext2. + { + if( iRandomPlayer == NO_INDEX ) // Si no se especificó un cliente aleatorio para la etiqueta, reemplaca la etiqueta y busca un cliente para la etiqueta. + { + iRandomPlayer = CFindRandomPlayerByTeam(CProfile_TeamIndex[i]); // Busca un cliente válido para la etiqueta, equipo de infectados oh supervivientes. + if( iRandomPlayer == NO_PLAYER ) + ReplaceString(sMessage, maxlength, CTag[i], CTagCode[5]); // Si no se encuentra un cliente valido, reemplasa la etiqueta con una etiqueta de color verde. + else + ReplaceString(sMessage, maxlength, CTag[i], CTagCode[i]); // Si el cliente fue encontrado simplemente reemplasa. + } + else // Si en caso de usar dos colores de equipo infectado y equipo de superviviente juntos se mandará un mensaje de error. + ThrowError("Using two team colors in one message is not allowed"); // Si se ha usadó una combinación de colores no validad se registrara en la carpeta logs. + } + } + + return iRandomPlayer; +} + +/** + * @note Founds a random player with specified team + * + * @param color_team Client team. + * @return Client index or NO_PLAYER if no player found + */ +stock int CFindRandomPlayerByTeam(int color_team) +{ + if( color_team == SERVER_INDEX ) + return 0; + else + for( int i = 1; i <= MaxClients; i++ ) + if( IsClientInGame(i) && GetClientTeam(i) == color_team ) + return i; + + return NO_PLAYER; +} + +/** + * @note Sends a SayText2 usermessage to a client + * + * @param sMessage Client index + * @param maxlength Author index + * @param sMessage Message + * @return No return. + */ +stock void CSayText2(int client, int author, const char[] sMessage) +{ + Handle hBuffer = StartMessageOne("SayText2", client); + BfWriteByte(hBuffer, author); + BfWriteByte(hBuffer, true); + BfWriteString(hBuffer, sMessage); + EndMessage(); +} + + + +// ==================================================================================================== +// TRANSLATE CODE +// ==================================================================================================== +// If using this code, you must replace the "\" character with "/" in the new "*phrases.txt.new" file. +stock void TranslateHatnames() +{ + int maxIndex = 95; // Searches from "1" to maxIndex (including max) in the "hatnames" file. Matches to the data config. + + char sLang[4] = "zho/"; // Language folder to translate. Blank for "en" + char sText[256]; + char sModel[PLATFORM_MAX_PATH]; + char sTran[PLATFORM_MAX_PATH]; + char sData[PLATFORM_MAX_PATH]; + char sSave[PLATFORM_MAX_PATH]; + + BuildPath(Path_SM, sSave, sizeof sSave, "translations/%shatnames.phrases.txt.new", sLang); + BuildPath(Path_SM, sTran, sizeof sTran, "translations/%shatnames.phrases.txt", sLang); + BuildPath(Path_SM, sData, sizeof sData, "data/l4d_hats.cfg"); + + KeyValues hTran = new KeyValues("Phrases"); + KeyValues hData = new KeyValues("Models"); + KeyValues hSave = new KeyValues("Phrases"); + + hTran.ImportFromFile(sTran); + hData.ImportFromFile(sData); + + char sIndex[16]; + + for( int i = 1; i <= maxIndex; i++ ) + { + IntToString(i, sIndex, sizeof sIndex); + hData.JumpToKey(sIndex); + hData.GetString("mod", sModel, sizeof(sModel)); + ReplaceString(sModel, sizeof sModel, "/", "\\"); + + Format(sIndex, sizeof sIndex, "Hat %d", i); + hTran.JumpToKey(sIndex); + hTran.GetString(sLang, sText, sizeof(sText)); + + PrintToServer("%02d (%s) [%s] == [%s]", i, sIndex, sModel, sText); + + hSave.JumpToKey(sModel, true); + hSave.SetString(sLang, sText); + + hTran.Rewind(); + hData.Rewind(); + hSave.Rewind(); + } + + hSave.ExportToFile(sSave); + + delete hTran; + delete hData; + delete hSave; +} \ No newline at end of file diff --git a/addons/sourcemod/translations/chi/hatnames.phrases.txt b/addons/sourcemod/translations/chi/hatnames.phrases.txt new file mode 100644 index 000000000..3686c9f05 --- /dev/null +++ b/addons/sourcemod/translations/chi/hatnames.phrases.txt @@ -0,0 +1,383 @@ +"Phrases" +{ + "models/infected/gibs/gibs.mdl" + { + "chi" "一手遮天" + } + "models/infected/limbs/exploded_boomer_head.mdl" + { + "chi" "Boomer 头" + } + "models/infected/limbs/limb_male_head01.mdl" + { + "chi" "假面" + } + "models/props/cs_militia/circularsaw01.mdl" + { + "chi" "圆锯" + } + "models/props/de_nuke/emergency_lighta.mdl" + { + "chi" "红色应急灯" + } + "models/props_fairgrounds/alligator.mdl" + { + "chi" "鳄鱼" + } + "models/props_fairgrounds/mr_mustachio.mdl" + { + "chi" "胡子先生" + } + "models/props_fortifications/orange_cone001_clientside.mdl" + { + "chi" "路障" + } + "models/props_interiors/teddy_bear.mdl" + { + "chi" "玩具熊" + } + "models/props_interiors/toilet_b_breakable01_part13.mdl" + { + "chi" "便器" + } + "models/props_interiors/waterbottle.mdl" + { + "chi" "水瓶" + } + "models/props_urban/dock_pylon_cap001.mdl" + { + "chi" "码头塔" + } + "models/props_urban/life_ring001.mdl" + { + "chi" "救生圈" + } + "models/props_lighting/light_construction02.mdl" + { + "chi" "建筑灯" + } + "models/extras/info_speech.mdl" + { + "chi" "聊天气泡" + } + "models/infected/smoker_tongue_attach.mdl" + { + "chi" "舌头" + } + "models/props/de_inferno/ceiling_fan_blade.mdl" + { + "chi" "吊扇叶片" + } + "models/f18/f18_placeholder.mdl" + { + "chi" "F-18 喷气式飞机" + } + "models/deadbodies/dead_male_civilian_radio.mdl" + { + "chi" "对讲机" + } + "models/infected/cim_riot_faceplate.mdl" + { + "chi" "防爆罩" + } + "models/props_interiors/styrofoam_cups.mdl" + { + "chi" "泡沫塑料杯" + } + "models/props_shacks/bug_lamp01.mdl" + { + "chi" "灭蚊灯" + } + "models/props_unique/grill_campground.mdl" + { + "chi" "烧烤架" + } + "models/props_unique/luggagecart01.mdl" + { + "chi" "超市手推车" + } + "models/props_unique/spawn_apartment/lantern.mdl" + { + "chi" "手提灯" + } + "models/props_urban/exit_sign002.mdl" + { + "chi" "出口标记" + } + "models/props_urban/garden_hose001.mdl" + { + "chi" "软管" + } + "models/props_urban/plastic_flamingo001.mdl" + { + "chi" "粉红火烈鸟" + } + "models/props_waterfront/money_pile.mdl" + { + "chi" "钱堆" + } + "models/props_fairgrounds/elephant.mdl" + { + "chi" "大象" + } + "models/props_fairgrounds/giraffe.mdl" + { + "chi" "长颈鹿" + } + "models/props_fairgrounds/garbage_popcorn_box.mdl" + { + "chi" "爆米花" + } + "models/props_fairgrounds/gnome_closet.mdl" + { + "chi" "矮人架" + } + "models/props_fairgrounds/snake.mdl" + { + "chi" "蛇" + } + "models/props_interiors/toaster.mdl" + { + "chi" "面包机" + } + "models/props_unique/doll01.mdl" + { + "chi" "娃娃" + } + "models/props_junk/garbage_hubcap01a.mdl" + { + "chi" "轮胎盖" + } + "models/props_mall/mall_mannequin_rhand.mdl" + { + "chi" "模型手" + } + "models/props_lab/desklamp01.mdl" + { + "chi" "台灯" + } + "models/props_vehicles/helicopter_rescue.mdl" + { + "chi" "大直升机" + } + "models/hybridphysx/news_helicoptor_map1_intro_v1.mdl" + { + "chi" "新闻直升机" + } + "models/missiles/f18_agm65maverick.mdl" + { + "chi" "导弹" + } + "models/props_vehicles/boat_fishing02.mdl" + { + "chi" "渔船" + } + "models/props_urban/big_wheel001.mdl" + { + "chi" "儿童三轮车" + } + "models/props_interiors/mounteddeerhead01.mdl" + { + "chi" "鹿头" + } + "models/props_misc/pot-1.mdl" + { + "chi" "平底锅" + } + "models/props_c17/metalpot002a.mdl" + { + "chi" "煎锅" + } + "models/gibs/hgibs.mdl" + { + "chi" "骷髅头" + } + "models/props/cs_militia/caseofbeer01.mdl" + { + "chi" "啤酒箱" + } + "models/props/cs_office/chair_office.mdl" + { + "chi" "办公椅子" + } + "models/props_cemetery/crypts_top02.mdl" + { + "chi" "墓地十字架" + } + "models/props_fairgrounds/kiddyland_riderocket_small.mdl" + { + "chi" "儿童乐园火箭" + } + "models/props_interiors/toilet_b_breakable01.mdl" + { + "chi" "厕所" + } + "models/props_misc/lamp-1_gib1.mdl" + { + "chi" "灯罩" + } + "models/props_misc/saddle-1.mdl" + { + "chi" "马鞍" + } + "models/props_unique/wheelchair01.mdl" + { + "chi" "轮椅" + } + "models/props_urban/mega_phone001.mdl" + { + "chi" "大喇叭" + } + "models/props/de_train/de_train_floodlights_01.mdl" + { + "chi" "泛光灯" + } + "models/props_vehicles/tire001c_car.mdl" + { + "chi" "汽车轮胎" + } + "models/props/de_inferno/ceiling_fan.mdl" + { + "chi" "吊扇" + } + "models/props/de_prodigy/fan.mdl" + { + "chi" "涡轮扇" + } + "models/props_foliage/urban_pot_clay01.mdl" + { + "chi" "盆栽植物 1" + } + "models/props_foliage/urban_pot_clay02.mdl" + { + "chi" "盆栽植物 2" + } + "models/props_downtown/ironing_board_flat.mdl" + { + "chi" "熨衣板" + } + "models/props_collectables/coin.mdl" + { + "chi" "金币" + } + "models/infected/jockey.mdl" + { + "chi" "Jockey" + } + "models/items/l4d_gift.mdl" + { + "chi" "礼物" + } + "models/props_street/firehydrant.mdl" + { + "chi" "消防栓" + } + "models/props_junk/gnome.mdl" + { + "chi" "矮人" + } + "models/bunny/b_sailboat.mdl" + { + "chi" "帆船" + } + "models/props/de_nuke/light_red2.mdl" + { + "chi" "红色舱壁灯" + } + "models/props_buildables/mine.mdl" + { + "chi" "轮毂盖" + } + "models/props_cemetery/crypts_top01.mdl" + { + "chi" "墓地十字架" + } + "models/props_misc/tea_pot-1.mdl" + { + "chi" "泡泡茶壶" + } + "models/props_fairgrounds/pyrotechnics_launcher.mdl" + { + "chi" "烟火" + } + "models/props_interiors/coffee_maker.mdl" + { + "chi" "咖啡机" + } + "models/props_interiors/pot01a.mdl" + { + "chi" "水壶" + } + "models/props_interiors/tv.mdl" + { + "chi" "电视" + } + "models/props_interiors/lamp_floor_gib2.mdl" + { + "chi" "灯罩 1" + } + "models/props_interiors/lamp_table02_gib2.mdl" + { + "chi" "灯罩 2" + } + "models/props_lighting/semi_flush_001.mdl" + { + "chi" "灯罩 3" + } + "models/props_junk/petfoodbag01.mdl" + { + "chi" "狗粮" + } + "models/props_lighting/flashlight_dropped_01.mdl" + { + "chi" "手电筒" + } + "models/props_lighting/lightfixture03.mdl" + { + "chi" "球灯" + } + "models/props_mall/cash_register.mdl" + { + "chi" "收银机" + } + "models/props_placeable/tier1_guns_trophy.mdl" + { + "chi" "枪架 1" + } + "models/props_placeable/tier2_guns_trophy.mdl" + { + "chi" "枪架 2" + } + "models/weapons/arms/v_spitter_arms.mdl" + { + "chi" "Spitter 手" + } + "models/weapons/arms/v_jockey_arms.mdl" + { + "chi" "Jockey 爪子" + } + "models/v_models/weapons/v_claw_hulk.mdl" + { + "chi" "Tank 爪子" + } + "models/w_models/weapons/w_he_grenade.mdl" + { + "chi" "炮弹" + } + "models/props_junk/propanecanister001a.mdl" + { + "chi" "丙烷气瓶" + } + "models/w_models/weapons/w_eq_medkit.mdl" + { + "chi" "医疗包帽" + } + "models/weapons/melee/w_riotshield.mdl" + { + "chi" "防爆盾" + } + "models/props_skybox/boat_rescue_tug_sunshine.mdl" + { + "chi" "游艇" + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/chi/hats.phrases.txt b/addons/sourcemod/translations/chi/hats.phrases.txt new file mode 100644 index 000000000..d51c187f4 --- /dev/null +++ b/addons/sourcemod/translations/chi/hats.phrases.txt @@ -0,0 +1,143 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "chi" "您正在配戴{ORANGE}{1}{DEFAULT}。" + } + "Hat_Changed" + { + "#format" "{1:s}" + "chi" "您正在配戴{ORANGE}{1}{DEFAULT}。" + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "chi" "无法找到编号为{ORANGE}{1}{DEFAULT}的帽子。 (应在{ORANGE}1{DEFAULT}至{ORANGE}{2}{DEFAULT}内)" + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "chi" "无法找到帽子{ORANGE}{1}{DEFAULT}。" + } + "Hat_Invalid" + { + "chi" "无效的玩家。" + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "chi" "Unblocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "chi" "Blocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "chi" "您已{ORANGE}{1}{DEFAULT}第一人称可见状态。" + } + "Hat_Ability" + { + "#format" "{1:s}" + "chi" "您已{ORANGE}{1}{DEFAULT}帽子穿戴功能。" + } + "Hat_On" + { + "chi" "启用" + } + "Hat_Off" + { + "chi" "停用" + } + "Hat_Menu_Title" + { + "chi" "选择帽子:" + } + "Hat_Missing" + { + "chi" "无法配戴帽子。" + } + + "HAT_SYSTEM" + { + "chi" "{GREEN}[帽子]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "chi" "暂时无法使用。" + } + "ADMIN_DISABLE_HAT" + { + "chi" "选择玩家停用帽子:" + } + "ADMIN_CHANGE_HAT" + { + "chi" "选择玩家更换帽子:" + } + "ADMIN_VISIBILITY" + { + "chi" "Select player to set hat visibility:" + } + "HAT_SET_ANGLE" + { + "chi" "选择帽子角度:" + } + "HAT_SET_POSITION" + { + "chi" "选择帽子位置:" + } + "HAT_SET_SIZE" + { + "chi" "选择帽子大细:" + } + "HAT_MAIN" + { + "chi" "选择动作:" + } + "HAT_MENU" + { + "chi" "打开帽子选单" + } + "HAT_WORE" + { + "chi" "穿戴状态" + } + "HAT_VIEWABLE" + { + "chi" "第一人称可见状态" + } + "HAT_ENABLED" + { + "chi" "已启用" + } + "HAT_DISABLED" + { + "chi" "己停用" + } + "HAT_VIEWABLE_TP" + { + "chi" "第三人称可见状态" + } + "HAT_VISIBILITY" + { + "chi" "颢示其他玩家的帽子" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "chi" "您已{ORANGE}{1}{DEFAULT}第三人称可见状态" + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "chi" "{ORANGE}{2}{DEFAULT}玩家{ORANGE}{1}{DEFAULT}颢示其他玩家的帽子" + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "chi" "显示其他玩家的帽子:{ORANGE}{1}{DEFAULT}" + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/de/hats.phrases.txt b/addons/sourcemod/translations/de/hats.phrases.txt new file mode 100644 index 000000000..b57a00e46 --- /dev/null +++ b/addons/sourcemod/translations/de/hats.phrases.txt @@ -0,0 +1,143 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "de" "Du trägst nun den {ORANGE}[{1}] {DEFAULT}Hut." + } + "Hat_Changed" + { + "#format" "{1:s}" + "de" "Hut von {ORANGE}{1}{DEFAULT} geändert." + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "de" "Kann den Hut Index {ORANGE}{1}{DEFAULT} nicht finden, Werte zwischen {ORANGE}1{DEFAULT} und {ORANGE}{2}{DEFAULT}." + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "de" "Kann den Hut {ORANGE}{1}{DEFAULT} nicht finden." + } + "Hat_Invalid" + { + "de" "Ungültigen Spieler ausgewählt." + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "de" "Hüte für {ORANGE}{1}{DEFAULT} wurden erlaubt." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "de" "Hüte für {ORANGE}{1}{DEFAULT} wurden verboten." + } + "Hat_View" + { + "#format" "{1:s}" + "de" "{DEFAULT}Sichtbarkeit des eigenen Hutes {ORANGE}{1}{DEFAULT}." + } + "Hat_Ability" + { + "#format" "{1:s}" + "de" "{DEFAULT}Du hast die Möglichkeit einen Hut zu tragen {ORANGE}{1}{DEFAULT}geschaltet." + } + "Hat_On" + { + "de" "ein" + } + "Hat_Off" + { + "de" "aus" + } + "Hat_Menu_Title" + { + "de" "Wähle deinen Hut." + } + "Hat_Missing" + { + "de" "Du trägst keinen Hut!" + } + + "HAT_SYSTEM" + { + "de" "{GREEN}[Hut]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "de" "Du kannst diesen Befehl derzeit nicht verwenden." + } + "ADMIN_DISABLE_HAT" + { + "de" "Wähle Spieler aus wessen Hut du deaktiiveren möchtest:" + } + "ADMIN_CHANGE_HAT" + { + "de" "Wähle Spieler aus wessen Hut du ändern möchtest:" + } + "ADMIN_VISIBILITY" + { + "de" "Wähle Spieler aus wessen Hut-Sichtbarkeit du ändern möchtest:" + } + "HAT_SET_ANGLE" + { + "de" "Setze Winkel:" + } + "HAT_SET_POSITION" + { + "de" "Setze Position:" + } + "HAT_SET_SIZE" + { + "de" "Setze Größe:" + } + "HAT_MAIN" + { + "de" "Hut Einstellungen:" + } + "HAT_MENU" + { + "de" "Öffne das Hut Menü" + } + "HAT_WORE" + { + "de" "Hut Tragen" + } + "HAT_VIEWABLE" + { + "de" "Persönliche Hutansicht" + } + "HAT_ENABLED" + { + "de" "Ein" + } + "HAT_DISABLED" + { + "de" "Aus" + } + "HAT_VIEWABLE_TP" + { + "de" "Dritte Person Hutansicht" + } + "HAT_VISIBILITY" + { + "de" "Allgemeine Hut Sichtbarkeit" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "de" "Sichtbarkeit des dritte Person Hutes {ORANGE}{1}{DEFAULT}geschaltet." + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "de" "Allgemeine Hutsichtbarkeit für {ORANGE}{1}{DEFAULT} wurde {ORANGE}{2}{DEFAULT}geschaltet." + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "de" "Du hast die Sichtbarkeit von Hüten {ORANGE}{1}{DEFAULT} geschaltet." + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/es/hatnames.phrases.txt b/addons/sourcemod/translations/es/hatnames.phrases.txt new file mode 100644 index 000000000..a9fcaffea --- /dev/null +++ b/addons/sourcemod/translations/es/hatnames.phrases.txt @@ -0,0 +1,383 @@ +"Phrases" +{ + "models/infected/gibs/gibs.mdl" + { + "es" "Mano Gib" + } + "models/infected/limbs/exploded_boomer_head.mdl" + { + "es" "Cabeza de Boomer" + } + "models/infected/limbs/limb_male_head01.mdl" + { + "es" "Cabeza Gib" + } + "models/props/cs_militia/circularsaw01.mdl" + { + "es" "Sierra Circular" + } + "models/props/de_nuke/emergency_lighta.mdl" + { + "es" "Luz de Emergencia Roja" + } + "models/props_fairgrounds/alligator.mdl" + { + "es" "Cocodrilo" + } + "models/props_fairgrounds/mr_mustachio.mdl" + { + "es" "Señor Bigote" + } + "models/props_fortifications/orange_cone001_clientside.mdl" + { + "es" "Cono de Tráfico" + } + "models/props_interiors/teddy_bear.mdl" + { + "es" "Osito de Peluche" + } + "models/props_interiors/toilet_b_breakable01_part13.mdl" + { + "es" "Asiento de Inodoro" + } + "models/props_interiors/waterbottle.mdl" + { + "es" "Botella de Agua" + } + "models/props_urban/dock_pylon_cap001.mdl" + { + "es" "Pilón de Muelle" + } + "models/props_urban/life_ring001.mdl" + { + "es" "Aro Salvavidas" + } + "models/props_lighting/light_construction02.mdl" + { + "es" "Luz de Construcción" + } + "models/extras/info_speech.mdl" + { + "es" "Cita de Discurso" + } + "models/infected/smoker_tongue_attach.mdl" + { + "es" "Lengua de Smoker" + } + "models/props/de_inferno/ceiling_fan_blade.mdl" + { + "es" "Aspas de Ventilador de Techo" + } + "models/f18/f18_placeholder.mdl" + { + "es" "Avión Jet F-18" + } + "models/deadbodies/dead_male_civilian_radio.mdl" + { + "es" "Radio Civil" + } + "models/infected/cim_riot_faceplate.mdl" + { + "es" "Placa de Cara de Riot" + } + "models/props_interiors/styrofoam_cups.mdl" + { + "es" "Vasos de Poliestireno" + } + "models/props_shacks/bug_lamp01.mdl" + { + "es" "Lámpara Mata Insectos" + } + "models/props_unique/grill_campground.mdl" + { + "es" "Asador" + } + "models/props_unique/luggagecart01.mdl" + { + "es" "Carrito de Equipaje" + } + "models/props_unique/spawn_apartment/lantern.mdl" + { + "es" "Lámpara" + } + "models/props_urban/exit_sign002.mdl" + { + "es" "Señal de Salida" + } + "models/props_urban/garden_hose001.mdl" + { + "es" "Manguera de Jardín" + } + "models/props_urban/plastic_flamingo001.mdl" + { + "es" "Flamenco Rosa" + } + "models/props_waterfront/money_pile.mdl" + { + "es" "Pila de Dinero" + } + "models/props_fairgrounds/elephant.mdl" + { + "es" "Elefante" + } + "models/props_fairgrounds/giraffe.mdl" + { + "es" "Jirafa" + } + "models/props_fairgrounds/garbage_popcorn_box.mdl" + { + "es" "Caja de Popcorn" + } + "models/props_fairgrounds/gnome_closet.mdl" + { + "es" "Armario de Gnome" + } + "models/props_fairgrounds/snake.mdl" + { + "es" "Serpiente" + } + "models/props_interiors/toaster.mdl" + { + "es" "Tostadora" + } + "models/props_unique/doll01.mdl" + { + "es" "Muñeca" + } + "models/props_junk/garbage_hubcap01a.mdl" + { + "es" "Tapa de Llanta" + } + "models/props_mall/mall_mannequin_rhand.mdl" + { + "es" "Mano de maniquí" + } + "models/props_lab/desklamp01.mdl" + { + "es" "Lámpara de Escritorio" + } + "models/props_vehicles/helicopter_rescue.mdl" + { + "es" "Helicóptero Grande" + } + "models/hybridphysx/news_helicoptor_map1_intro_v1.mdl" + { + "es" "Helicóptero de Noticias" + } + "models/missiles/f18_agm65maverick.mdl" + { + "es" "Missil" + } + "models/props_vehicles/boat_fishing02.mdl" + { + "es" "Barco de Pesca" + } + "models/props_urban/big_wheel001.mdl" + { + "es" "Triciclo de Niño" + } + "models/props_interiors/mounteddeerhead01.mdl" + { + "es" "Cabeza de Ciervo" + } + "models/props_misc/pot-1.mdl" + { + "es" "Cacerola" + } + "models/props_c17/metalpot002a.mdl" + { + "es" "Sartén" + } + "models/gibs/hgibs.mdl" + { + "es" "Cráneo" + } + "models/props/cs_militia/caseofbeer01.mdl" + { + "es" "Caja de Cerveza" + } + "models/props/cs_office/chair_office.mdl" + { + "es" "Silla de Oficina" + } + "models/props_cemetery/crypts_top02.mdl" + { + "es" "Cruz de Cementerio" + } + "models/props_fairgrounds/kiddyland_riderocket_small.mdl" + { + "es" "Cohete de Kiddyland" + } + "models/props_interiors/toilet_b_breakable01.mdl" + { + "es" "Inodoro" + } + "models/props_misc/lamp-1_gib1.mdl" + { + "es" "Pantalla de Lámpara" + } + "models/props_misc/saddle-1.mdl" + { + "es" "Montura" + } + "models/props_unique/wheelchair01.mdl" + { + "es" "Silla de Ruedas" + } + "models/props_urban/mega_phone001.mdl" + { + "es" "Megáfono" + } + "models/props/de_train/de_train_floodlights_01.mdl" + { + "es" "Focos de Luz" + } + "models/props_vehicles/tire001c_car.mdl" + { + "es" "Llanta de Carro" + } + "models/props/de_inferno/ceiling_fan.mdl" + { + "es" "Ventilador de Techo" + } + "models/props/de_prodigy/fan.mdl" + { + "es" "Ventilador" + } + "models/props_foliage/urban_pot_clay01.mdl" + { + "es" "Maceta 1" + } + "models/props_foliage/urban_pot_clay02.mdl" + { + "es" "Maceta 2" + } + "models/props_downtown/ironing_board_flat.mdl" + { + "es" "Tabla de Planchar" + } + "models/props_collectables/coin.mdl" + { + "es" "Moneda" + } + "models/infected/jockey.mdl" + { + "es" "Jockey" + } + "models/items/l4d_gift.mdl" + { + "es" "Regalo" + } + "models/props_street/firehydrant.mdl" + { + "es" "Boca de Incendios" + } + "models/props_junk/gnome.mdl" + { + "es" "Gnome" + } + "models/bunny/b_sailboat.mdl" + { + "es" "Barco de Vela" + } + "models/props/de_nuke/light_red2.mdl" + { + "es" "Luz de Bodega Roja" + } + "models/props_buildables/mine.mdl" + { + "es" "Tapa de Llanta" + } + "models/props_cemetery/crypts_top01.mdl" + { + "es" "Cruz de Cementerio" + } + "models/props_misc/tea_pot-1.mdl" + { + "es" "Tetera" + } + "models/props_fairgrounds/pyrotechnics_launcher.mdl" + { + "es" "Pirotecnia" + } + "models/props_interiors/coffee_maker.mdl" + { + "es" "Cafetera" + } + "models/props_interiors/pot01a.mdl" + { + "es" "Tetera" + } + "models/props_interiors/tv.mdl" + { + "es" "Televisión" + } + "models/props_interiors/lamp_floor_gib2.mdl" + { + "es" "Pantalla de Lámpara 1" + } + "models/props_interiors/lamp_table02_gib2.mdl" + { + "es" "Pantalla de Lámpara 2" + } + "models/props_lighting/semi_flush_001.mdl" + { + "es" "Pantalla de Lámpara 3" + } + "models/props_junk/petfoodbag01.mdl" + { + "es" "Comida de Perro" + } + "models/props_lighting/flashlight_dropped_01.mdl" + { + "es" "Linterna Dalek" + } + "models/props_lighting/lightfixture03.mdl" + { + "es" "Luz de Bola" + } + "models/props_mall/cash_register.mdl" + { + "es" "Caja Registradora" + } + "models/props_placeable/tier1_guns_trophy.mdl" + { + "es" "Trofeo de Arma 1" + } + "models/props_placeable/tier2_guns_trophy.mdl" + { + "es" "Trofeo de Arma 2" + } + "models/weapons/arms/v_spitter_arms.mdl" + { + "es" "Brazos de Spitter" + } + "models/weapons/arms/v_jockey_arms.mdl" + { + "es" "Garras de Jockey" + } + "models/v_models/weapons/v_claw_hulk.mdl" + { + "es" "Garras de Tank" + } + "models/w_models/weapons/w_he_grenade.mdl" + { + "es" "Granada" + } + "models/props_junk/propanecanister001a.mdl" + { + "es" "Cilindro de Propano" + } + "models/w_models/weapons/w_eq_medkit.mdl" + { + "es" "Botiquín" + } + "models/weapons/melee/w_riotshield.mdl" + { + "es" "Escudo Antidisturbios" + } + "models/props_skybox/boat_rescue_tug_sunshine.mdl" + { + "es" "Barco Remolcador" + } +} diff --git a/addons/sourcemod/translations/es/hats.phrases.txt b/addons/sourcemod/translations/es/hats.phrases.txt new file mode 100644 index 000000000..2cc5f682b --- /dev/null +++ b/addons/sourcemod/translations/es/hats.phrases.txt @@ -0,0 +1,143 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "es" "Ahora llevas el sombrero {ORANGE}[{1}] {DEFAULT}." + } + "Hat_Changed" + { + "#format" "{1:s}" + "es" "Cambio de sombrero en {ORANGE}{1}{DEFAULT}." + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "es" "No se encuentra el índice {ORANGE}{1}{DEFAULT}, valores entre {ORANGE}1{DEFAULT} y {ORANGE}{2}{DEFAULT}." + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "es" "No se encuentra el sombrero {ORANGE}{1}{DEFAULT}." + } + "Hat_Invalid" + { + "es" "Jugador no válido seleccionado." + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "es" "Sombreros desbloqueados para {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "es" "Sombreros bloqueados para {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "es" "{DEFAULT}La vista personal se ha convertido {ORANGE}{1}{DEFAULT}." + } + "Hat_Ability" + { + "#format" "{1:s}" + "es" "{DEFAULT}Se ha convertido en {ORANGE}{1}{DEFAULT} la capacidad de usar sombreros." + } + "Hat_On" + { + "es" "Activado" + } + "Hat_Off" + { + "es" "Desactivado" + } + "Hat_Menu_Title" + { + "es" "Seleccione su sombrero." + } + "Hat_Missing" + { + "es" "¡No llevas sombrero!" + } + + "HAT_SYSTEM" + { + "es" "{GREEN}[HAT]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "es" "No puedo usar este comando en este momento." + } + "ADMIN_DISABLE_HAT" + { + "es" "Selecciona jugador para desactivar:" + } + "ADMIN_CHANGE_HAT" + { + "es" "Selecciona jugador para cambiar:" + } + "ADMIN_VISIBILITY" + { + "es" "Selecciona jugador para configurar la visibilidad:" + } + "HAT_SET_ANGLE" + { + "es" "Establecer ángulo:" + } + "HAT_SET_POSITION" + { + "es" "Posición de ajuste:" + } + "HAT_SET_SIZE" + { + "es" "Establecer tamaño:" + } + "HAT_MAIN" + { + "es" "Configuración:" + } + "HAT_MENU" + { + "es" "Menú de sombreros" + } + "HAT_WORE" + { + "es" "Uso" + } + "HAT_VIEWABLE" + { + "es" "Vista personal" + } + "HAT_ENABLED" + { + "es" "Activado" + } + "HAT_DISABLED" + { + "es" "Desactivado" + } + "HAT_VIEWABLE_TP" + { + "es" "Tercera persona" + } + "HAT_VISIBILITY" + { + "es" "Visibilidad general" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "es" "La vista de sombrero en tercera persona se ha cambiado a {ORANGE}{1}{DEFAULT}." + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "es" "La visibilidad general para {ORANGE}{1}{DEFAULT} se ha convertido en {ORANGE}{2}{DEFAULT}." + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "es" "Has cambiado la visibilidad de los sombreros a {ORANGE}{1}{DEFAULT}." + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/hatnames.phrases.txt b/addons/sourcemod/translations/hatnames.phrases.txt new file mode 100644 index 000000000..042954d91 --- /dev/null +++ b/addons/sourcemod/translations/hatnames.phrases.txt @@ -0,0 +1,383 @@ +"Phrases" +{ + "models/infected/gibs/gibs.mdl" + { + "en" "Hand Gib" + } + "models/infected/limbs/exploded_boomer_head.mdl" + { + "en" "Boomer Head" + } + "models/infected/limbs/limb_male_head01.mdl" + { + "en" "Head Gib" + } + "models/props/cs_militia/circularsaw01.mdl" + { + "en" "Circular Saw" + } + "models/props/de_nuke/emergency_lighta.mdl" + { + "en" "Red Emergency Light" + } + "models/props_fairgrounds/alligator.mdl" + { + "en" "Alligator" + } + "models/props_fairgrounds/mr_mustachio.mdl" + { + "en" "Mr Mustachio" + } + "models/props_fortifications/orange_cone001_clientside.mdl" + { + "en" "Traffic Cone" + } + "models/props_interiors/teddy_bear.mdl" + { + "en" "Teddy Bear" + } + "models/props_interiors/toilet_b_breakable01_part13.mdl" + { + "en" "Toilet Seat" + } + "models/props_interiors/waterbottle.mdl" + { + "en" "Water bottle" + } + "models/props_urban/dock_pylon_cap001.mdl" + { + "en" "Dock Pylon" + } + "models/props_urban/life_ring001.mdl" + { + "en" "Life Ring" + } + "models/props_lighting/light_construction02.mdl" + { + "en" "Construction Light" + } + "models/extras/info_speech.mdl" + { + "en" "Speech Quote" + } + "models/infected/smoker_tongue_attach.mdl" + { + "en" "Smoker Tongue" + } + "models/props/de_inferno/ceiling_fan_blade.mdl" + { + "en" "Ceiling Fan Blades" + } + "models/f18/f18_placeholder.mdl" + { + "en" "F-18 Jet Plane" + } + "models/deadbodies/dead_male_civilian_radio.mdl" + { + "en" "Civilian Radio" + } + "models/infected/cim_riot_faceplate.mdl" + { + "en" "Riot Faceplate" + } + "models/props_interiors/styrofoam_cups.mdl" + { + "en" "Styrofoam Cups" + } + "models/props_shacks/bug_lamp01.mdl" + { + "en" "Bug Lamp Zapper" + } + "models/props_unique/grill_campground.mdl" + { + "en" "BBQ Grill" + } + "models/props_unique/luggagecart01.mdl" + { + "en" "Luggage Cart" + } + "models/props_unique/spawn_apartment/lantern.mdl" + { + "en" "Lantern" + } + "models/props_urban/exit_sign002.mdl" + { + "en" "Exit Sign" + } + "models/props_urban/garden_hose001.mdl" + { + "en" "Garden Hose" + } + "models/props_urban/plastic_flamingo001.mdl" + { + "en" "Pink Flamingo" + } + "models/props_waterfront/money_pile.mdl" + { + "en" "Money Pile" + } + "models/props_fairgrounds/elephant.mdl" + { + "en" "Elephant" + } + "models/props_fairgrounds/giraffe.mdl" + { + "en" "Giraffe" + } + "models/props_fairgrounds/garbage_popcorn_box.mdl" + { + "en" "Popcorn Box" + } + "models/props_fairgrounds/gnome_closet.mdl" + { + "en" "Gnome Closet" + } + "models/props_fairgrounds/snake.mdl" + { + "en" "Snake" + } + "models/props_interiors/toaster.mdl" + { + "en" "Toaster" + } + "models/props_unique/doll01.mdl" + { + "en" "Doll" + } + "models/props_junk/garbage_hubcap01a.mdl" + { + "en" "Hub Cap" + } + "models/props_mall/mall_mannequin_rhand.mdl" + { + "en" "Mannequin Hand" + } + "models/props_lab/desklamp01.mdl" + { + "en" "Desk Lamp" + } + "models/props_vehicles/helicopter_rescue.mdl" + { + "en" "Big Helicopter" + } + "models/hybridphysx/news_helicoptor_map1_intro_v1.mdl" + { + "en" "News Helicopter" + } + "models/missiles/f18_agm65maverick.mdl" + { + "en" "Missile" + } + "models/props_vehicles/boat_fishing02.mdl" + { + "en" "Fishing Boat" + } + "models/props_urban/big_wheel001.mdl" + { + "en" "Childs Trike" + } + "models/props_interiors/mounteddeerhead01.mdl" + { + "en" "Deer Head" + } + "models/props_misc/pot-1.mdl" + { + "en" "Saucepan" + } + "models/props_c17/metalpot002a.mdl" + { + "en" "Frying Pan" + } + "models/gibs/hgibs.mdl" + { + "en" "Skull" + } + "models/props/cs_militia/caseofbeer01.mdl" + { + "en" "Case of Beer" + } + "models/props/cs_office/chair_office.mdl" + { + "en" "Office Chair" + } + "models/props_cemetery/crypts_top02.mdl" + { + "en" "Graveyard Cross" + } + "models/props_fairgrounds/kiddyland_riderocket_small.mdl" + { + "en" "Kiddyland Rocket" + } + "models/props_interiors/toilet_b_breakable01.mdl" + { + "en" "Toilet" + } + "models/props_misc/lamp-1_gib1.mdl" + { + "en" "Lamp Shade" + } + "models/props_misc/saddle-1.mdl" + { + "en" "Saddle" + } + "models/props_unique/wheelchair01.mdl" + { + "en" "Wheel Chair" + } + "models/props_urban/mega_phone001.mdl" + { + "en" "Mega Phone" + } + "models/props/de_train/de_train_floodlights_01.mdl" + { + "en" "Flood lights" + } + "models/props_vehicles/tire001c_car.mdl" + { + "en" "Car Tire" + } + "models/props/de_inferno/ceiling_fan.mdl" + { + "en" "Ceiling Fan" + } + "models/props/de_prodigy/fan.mdl" + { + "en" "Fan" + } + "models/props_foliage/urban_pot_clay01.mdl" + { + "en" "Pot Plant 1" + } + "models/props_foliage/urban_pot_clay02.mdl" + { + "en" "Pot Plant 2" + } + "models/props_downtown/ironing_board_flat.mdl" + { + "en" "Ironing Board" + } + "models/props_collectables/coin.mdl" + { + "en" "Coin" + } + "models/infected/jockey.mdl" + { + "en" "Jockey" + } + "models/items/l4d_gift.mdl" + { + "en" "Gift" + } + "models/props_street/firehydrant.mdl" + { + "en" "Fire Hydrant" + } + "models/props_junk/gnome.mdl" + { + "en" "Gnome" + } + "models/bunny/b_sailboat.mdl" + { + "en" "Sail Boat" + } + "models/props/de_nuke/light_red2.mdl" + { + "en" "Red Bulkhead Light" + } + "models/props_buildables/mine.mdl" + { + "en" "Wheel Hubcap" + } + "models/props_cemetery/crypts_top01.mdl" + { + "en" "Graveyard Cross" + } + "models/props_misc/tea_pot-1.mdl" + { + "en" "Tea Pot" + } + "models/props_fairgrounds/pyrotechnics_launcher.mdl" + { + "en" "Pyrotechnics" + } + "models/props_interiors/coffee_maker.mdl" + { + "en" "Coffee Maker" + } + "models/props_interiors/pot01a.mdl" + { + "en" "Kettle" + } + "models/props_interiors/tv.mdl" + { + "en" "TV" + } + "models/props_interiors/lamp_floor_gib2.mdl" + { + "en" "Lamp Shade 1" + } + "models/props_interiors/lamp_table02_gib2.mdl" + { + "en" "Lamp Shade 2" + } + "models/props_lighting/semi_flush_001.mdl" + { + "en" "Lamp Shade 3" + } + "models/props_junk/petfoodbag01.mdl" + { + "en" "Dog Food" + } + "models/props_lighting/flashlight_dropped_01.mdl" + { + "en" "Dalek Flash Light" + } + "models/props_lighting/lightfixture03.mdl" + { + "en" "Ball Light" + } + "models/props_mall/cash_register.mdl" + { + "en" "Cash Register" + } + "models/props_placeable/tier1_guns_trophy.mdl" + { + "en" "Gun Trophy 1" + } + "models/props_placeable/tier2_guns_trophy.mdl" + { + "en" "Gun Trophy 2" + } + "models/weapons/arms/v_spitter_arms.mdl" + { + "en" "Spitter Arms" + } + "models/weapons/arms/v_jockey_arms.mdl" + { + "en" "Jockey Claws" + } + "models/v_models/weapons/v_claw_hulk.mdl" + { + "en" "Tank Claws" + } + "models/w_models/weapons/w_he_grenade.mdl" + { + "en" "Grenade Shell" + } + "models/props_junk/propanecanister001a.mdl" + { + "en" "Propane Cylinder" + } + "models/w_models/weapons/w_eq_medkit.mdl" + { + "en" "Medkit Cap" + } + "models/weapons/melee/w_riotshield.mdl" + { + "en" "Riot Shield" + } + "models/props_skybox/boat_rescue_tug_sunshine.mdl" + { + "en" "Tug Boat" + } +} diff --git a/addons/sourcemod/translations/hats.phrases.txt b/addons/sourcemod/translations/hats.phrases.txt new file mode 100644 index 000000000..40c567f14 --- /dev/null +++ b/addons/sourcemod/translations/hats.phrases.txt @@ -0,0 +1,143 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "en" "You are now wearing the {ORANGE}[{1}] {DEFAULT}hat." + } + "Hat_Changed" + { + "#format" "{1:s}" + "en" "Changed hat on {ORANGE}{1}{DEFAULT}." + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "en" "Cannot find the hat index {ORANGE}{1}{DEFAULT}, values between {ORANGE}1{DEFAULT} and {ORANGE}{2}{DEFAULT}." + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "en" "Cannot find the hat {ORANGE}{1}{DEFAULT}." + } + "Hat_Invalid" + { + "en" "Invalid player selected." + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "en" "Unblocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "en" "Blocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "en" "Personal hat view has been turned {ORANGE}{1}{DEFAULT}." + } + "Hat_Ability" + { + "#format" "{1:s}" + "en" "You have turned {ORANGE}{1}{DEFAULT} the ability to wear hats." + } + "Hat_On" + { + "en" "on" + } + "Hat_Off" + { + "en" "off" + } + "Hat_Menu_Title" + { + "en" "Select your hat." + } + "Hat_Missing" + { + "en" "You're not wearing a hat!" + } + + "HAT_SYSTEM" + { + "en" "{GREEN}[HAT]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "en" "Can't use this command at the moment." + } + "ADMIN_DISABLE_HAT" + { + "en" "Select player to disable hats:" + } + "ADMIN_CHANGE_HAT" + { + "en" "Select player to change hat:" + } + "ADMIN_VISIBILITY" + { + "en" "Select player to set hat visibility:" + } + "HAT_SET_ANGLE" + { + "en" "Set Angle:" + } + "HAT_SET_POSITION" + { + "en" "Set Position:" + } + "HAT_SET_SIZE" + { + "en" "Set Size:" + } + "HAT_MAIN" + { + "en" "Hat Settings:" + } + "HAT_MENU" + { + "en" "Open Hats Menu" + } + "HAT_WORE" + { + "en" "Hat Wearing" + } + "HAT_VIEWABLE" + { + "en" "Personal Hat View" + } + "HAT_ENABLED" + { + "en" "On" + } + "HAT_DISABLED" + { + "en" "Off" + } + "HAT_VIEWABLE_TP" + { + "en" "Third Personal Hat View" + } + "HAT_VISIBILITY" + { + "en" "General Hat Visibility" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "en" "Third person hat view has been turned {ORANGE}{1}{DEFAULT}." + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "en" "General hat visibility for {ORANGE}{1}{DEFAULT} has been turned {ORANGE}{2}{DEFAULT}." + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "en" "You have turned the visibility of hats to {ORANGE}{1}{DEFAULT}." + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/ru/hats.phrases.txt b/addons/sourcemod/translations/ru/hats.phrases.txt new file mode 100644 index 000000000..f2b6fcfc3 --- /dev/null +++ b/addons/sourcemod/translations/ru/hats.phrases.txt @@ -0,0 +1,142 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "ru" "Вы надели шляпу: {ORANGE}[{1}] {DEFAULT}" + } + "Hat_Changed" + { + "#format" "{1:s}" + "ru" "Шапка заменена у {ORANGE}{1}{DEFAULT}." + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "ru" "Не могу найти индекс шапки {ORANGE}{1}{DEFAULT}, значения между {ORANGE}1{DEFAULT} и {ORANGE}{2}{DEFAULT}." + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "ru" "Не могу найти шапку {ORANGE}{1}{DEFAULT}." + } + "Hat_Invalid" + { + "ru" "Выбран неверный игрок." + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "ru" "Разблокированы шапки для {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "ru" "Заблокированы шапки для {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "ru" "{DEFAULT}Возможность видеть свою шапку: {ORANGE}{1}." + } + "Hat_Ability" + { + "#format" "{1:s}" + "ru" "{DEFAULT}Возможность надевать шапки: {ORANGE}{1}." + } + "Hat_On" + { + "ru" "включена" + } + "Hat_Off" + { + "ru" "отключена" + } + "Hat_Menu_Title" + { + "ru" "Выберите свою шляпу." + } + "Hat_Missing" + { + "ru" "На вас не одета шляпа!" + } + "HAT_SYSTEM" + { + "ru" "{GREEN}[Шляпа]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "ru" "Нельзя использовать эту команду в данный момент." + } + "ADMIN_DISABLE_HAT" + { + "ru" "Выберите игрока для отключения шапки:" + } + "ADMIN_CHANGE_HAT" + { + "ru" "Выберите игрока для изменения шапки:" + } + "ADMIN_VISIBILITY" + { + "ru" "Выберите игрока для установки видимости шапки:" + } + "HAT_SET_ANGLE" + { + "ru" "Задать угол:" + } + "HAT_SET_POSITION" + { + "ru" "Задать позицию:" + } + "HAT_SET_SIZE" + { + "ru" "Задать размер:" + } + "HAT_MAIN" + { + "ru" "Настройки шапки:" + } + "HAT_MENU" + { + "ru" "Открыть меню шапок" + } + "HAT_WORE" + { + "ru" "Надевание шапки" + } + "HAT_VIEWABLE" + { + "ru" "Вид шапки от 1-го лица" + } + "HAT_ENABLED" + { + "ru" "Включено" + } + "HAT_DISABLED" + { + "ru" "Отключено" + } + "HAT_VIEWABLE_TP" + { + "ru" "Вид шапки от 3-го лица" + } + "HAT_VISIBILITY" + { + "ru" "Общая видимость шапки" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "ru" "Вид шапки от 3-го лица был {ORANGE}{1}{DEFAULT}." + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "ru" "Общий вид шапки для {ORANGE}{1}{DEFAULT} был {ORANGE}{2}{DEFAULT}." + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "ru" "Видимость шапки теперь {ORANGE}{1}{DEFAULT}." + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/ua/hats.phrases.txt b/addons/sourcemod/translations/ua/hats.phrases.txt new file mode 100644 index 000000000..660ee2e84 --- /dev/null +++ b/addons/sourcemod/translations/ua/hats.phrases.txt @@ -0,0 +1,142 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "ua" "Ви одягнули капелюх: {ORANGE}[{1}] {DEFAULT}" + } + "Hat_Changed" + { + "#format" "{1:s}" + "ua" "Шапка замінена у {ORANGE}{1}{DEFAULT}." + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "ua" "Не можу знайти індекс шапки {ORANGE}{1}{DEFAULT}, значення між {ORANGE}1{DEFAULT} і {ORANGE}{2}{DEFAULT}." + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "ua" "Не можу знайти шапку {ORANGE}{1}{DEFAULT}." + } + "Hat_Invalid" + { + "ua" "Обрано невірного гравця." + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "ua" "Розблоковані шапки для {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "ua" "Заблоковані шапки для {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "ua" "{DEFAULT}Можливість бачити свою шапку: {ORANGE}{1}." + } + "Hat_Ability" + { + "#format" "{1:s}" + "ua" "{DEFAULT}Можливість вдягати шапки: {ORANGE}{1}." + } + "Hat_On" + { + "ua" "увімкнена" + } + "Hat_Off" + { + "ua" "відключена" + } + "Hat_Menu_Title" + { + "ua" "Оберіть свій капелюх." + } + "Hat_Missing" + { + "ua" "На вас не вдягнений капелюх!" + } + "HAT_SYSTEM" + { + "ua" "{GREEN}[Капелюх]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "ua" "Неможливо застосувати дану команду в цей чай." + } + "ADMIN_DISABLE_HAT" + { + "ua" "Оберіть гравця для відключення шапки:" + } + "ADMIN_CHANGE_HAT" + { + "ua" "Оберіть гравця для зміни шапки:" + } + "ADMIN_VISIBILITY" + { + "ua" "Оберіть гравця для встановлення бачення шапки:" + } + "HAT_SET_ANGLE" + { + "ua" "Встановити кут:" + } + "HAT_SET_POSITION" + { + "ua" "Встановити позицію:" + } + "HAT_SET_SIZE" + { + "ua" "Встановити розмір:" + } + "HAT_MAIN" + { + "ua" "Налаштування шапки:" + } + "HAT_MENU" + { + "ua" "Відкрити меню шапок" + } + "HAT_WORE" + { + "ua" "Вдягання шапки" + } + "HAT_VIEWABLE" + { + "ua" "Вигляд капелюха від 1-го лиця" + } + "HAT_ENABLED" + { + "ua" "Увімкнено" + } + "HAT_DISABLED" + { + "ua" "Відключено" + } + "HAT_VIEWABLE_TP" + { + "ua" "Вигляд капелюха від 3-го лиця" + } + "HAT_VISIBILITY" + { + "ua" "Загальне бачення капелюха" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "ua" "Вигляд капелюха від 3-го лиця {ORANGE}{1}{DEFAULT}." + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "ua" "Вигляд капелюха від 3-го лиця для {ORANGE}{1}{DEFAULT} було {ORANGE}{2}{DEFAULT}." + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "ua" "Бачення капелюха тепер {ORANGE}{1}{DEFAULT}." + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/zho/hatnames.phrases.txt b/addons/sourcemod/translations/zho/hatnames.phrases.txt new file mode 100644 index 000000000..89f652e93 --- /dev/null +++ b/addons/sourcemod/translations/zho/hatnames.phrases.txt @@ -0,0 +1,383 @@ +"Phrases" +{ + "models/infected/gibs/gibs.mdl" + { + "zho" "隻手遮天" + } + "models/infected/limbs/exploded_boomer_head.mdl" + { + "zho" "Boomer的頭" + } + "models/infected/limbs/limb_male_head01.mdl" + { + "zho" "假面" + } + "models/props/cs_militia/circularsaw01.mdl" + { + "zho" "圓鋸" + } + "models/props/de_nuke/emergency_lighta.mdl" + { + "zho" "紅色應急燈" + } + "models/props_fairgrounds/alligator.mdl" + { + "zho" "鱷魚布偶" + } + "models/props_fairgrounds/mr_mustachio.mdl" + { + "zho" "鬍子先生" + } + "models/props_fortifications/orange_cone001_clientside.mdl" + { + "zho" "交通錐" + } + "models/props_interiors/teddy_bear.mdl" + { + "zho" "玩具熊" + } + "models/props_interiors/toilet_b_breakable01_part13.mdl" + { + "zho" "馬桶座圈" + } + "models/props_interiors/waterbottle.mdl" + { + "zho" "礦泉水瓶" + } + "models/props_urban/dock_pylon_cap001.mdl" + { + "zho" "碼頭塔" + } + "models/props_urban/life_ring001.mdl" + { + "zho" "救生圈" + } + "models/props_lighting/light_construction02.mdl" + { + "zho" "施工燈" + } + "models/extras/info_speech.mdl" + { + "zho" "我無言了" + } + "models/infected/smoker_tongue_attach.mdl" + { + "zho" "Smoker的舌頭" + } + "models/props/de_inferno/ceiling_fan_blade.mdl" + { + "zho" "吊扇葉片" + } + "models/f18/f18_placeholder.mdl" + { + "zho" "F-18噴氣式飛機" + } + "models/deadbodies/dead_male_civilian_radio.mdl" + { + "zho" "對講機" + } + "models/infected/cim_riot_faceplate.mdl" + { + "zho" "防暴面板" + } + "models/props_interiors/styrofoam_cups.mdl" + { + "zho" "發泡膠杯" + } + "models/props_shacks/bug_lamp01.mdl" + { + "zho" "驅蟲燈" + } + "models/props_unique/grill_campground.mdl" + { + "zho" "燒烤架" + } + "models/props_unique/luggagecart01.mdl" + { + "zho" "購物車" + } + "models/props_unique/spawn_apartment/lantern.mdl" + { + "zho" "燈籠" + } + "models/props_urban/exit_sign002.mdl" + { + "zho" "出口指示牌" + } + "models/props_urban/garden_hose001.mdl" + { + "zho" "園藝軟管" + } + "models/props_urban/plastic_flamingo001.mdl" + { + "zho" "粉紅天鵝" + } + "models/props_waterfront/money_pile.mdl" + { + "zho" "錢堆" + } + "models/props_fairgrounds/elephant.mdl" + { + "zho" "大象布偶" + } + "models/props_fairgrounds/giraffe.mdl" + { + "zho" "長頸鹿布偶" + } + "models/props_fairgrounds/garbage_popcorn_box.mdl" + { + "zho" "爆米花盒" + } + "models/props_fairgrounds/gnome_closet.mdl" + { + "zho" "小矮人的櫃子" + } + "models/props_fairgrounds/snake.mdl" + { + "zho" "蛇布偶" + } + "models/props_interiors/toaster.mdl" + { + "zho" "烤麵包機" + } + "models/props_unique/doll01.mdl" + { + "zho" "玩具娃娃" + } + "models/props_junk/garbage_hubcap01a.mdl" + { + "zho" "輪轂蓋" + } + "models/props_mall/mall_mannequin_rhand.mdl" + { + "zho" "模型手" + } + "models/props_lab/desklamp01.mdl" + { + "zho" "檯燈" + } + "models/props_vehicles/helicopter_rescue.mdl" + { + "zho" "大直升機" + } + "models/hybridphysx/news_helicoptor_map1_intro_v1.mdl" + { + "zho" "新聞直升機" + } + "models/missiles/f18_agm65maverick.mdl" + { + "zho" "導彈" + } + "models/props_vehicles/boat_fishing02.mdl" + { + "zho" "漁船" + } + "models/props_urban/big_wheel001.mdl" + { + "zho" "兒童三輪車" + } + "models/props_interiors/mounteddeerhead01.mdl" + { + "zho" "鹿頭布偶" + } + "models/props_misc/pot-1.mdl" + { + "zho" "平底鍋" + } + "models/props_c17/metalpot002a.mdl" + { + "zho" "煎鍋" + } + "models/gibs/hgibs.mdl" + { + "zho" "顱骨" + } + "models/props/cs_militia/caseofbeer01.mdl" + { + "zho" "啤酒箱" + } + "models/props/cs_office/chair_office.mdl" + { + "zho" "辦公椅子" + } + "models/props_cemetery/crypts_top02.mdl" + { + "zho" "墓地十字架" + } + "models/props_fairgrounds/kiddyland_riderocket_small.mdl" + { + "zho" "兒童樂園火箭" + } + "models/props_interiors/toilet_b_breakable01.mdl" + { + "zho" "馬桶" + } + "models/props_misc/lamp-1_gib1.mdl" + { + "zho" "燈罩" + } + "models/props_misc/saddle-1.mdl" + { + "zho" "馬鞍" + } + "models/props_unique/wheelchair01.mdl" + { + "zho" "輪椅" + } + "models/props_urban/mega_phone001.mdl" + { + "zho" "擴音器" + } + "models/props/de_train/de_train_floodlights_01.mdl" + { + "zho" "投光燈" + } + "models/props_vehicles/tire001c_car.mdl" + { + "zho" "汽車輪胎" + } + "models/props/de_inferno/ceiling_fan.mdl" + { + "zho" "吊扇" + } + "models/props/de_prodigy/fan.mdl" + { + "zho" "風扇" + } + "models/props_foliage/urban_pot_clay01.mdl" + { + "zho" "盆栽植物1" + } + "models/props_foliage/urban_pot_clay02.mdl" + { + "zho" "盆栽植物2" + } + "models/props_downtown/ironing_board_flat.mdl" + { + "zho" "熨衣板" + } + "models/props_collectables/coin.mdl" + { + "zho" "金幣" + } + "models/infected/jockey.mdl" + { + "zho" "迷你Jockey" + } + "models/items/l4d_gift.mdl" + { + "zho" "禮物盒" + } + "models/props_street/firehydrant.mdl" + { + "zho" "消防栓" + } + "models/props_junk/gnome.mdl" + { + "zho" "小矮人" + } + "models/bunny/b_sailboat.mdl" + { + "zho" "帆船" + } + "models/props/de_nuke/light_red2.mdl" + { + "zho" "紅色隔板燈" + } + "models/props_buildables/mine.mdl" + { + "zho" "輪轂罩" + } + "models/props_cemetery/crypts_top01.mdl" + { + "zho" "墓地十字架" + } + "models/props_misc/tea_pot-1.mdl" + { + "zho" "茶壺" + } + "models/props_fairgrounds/pyrotechnics_launcher.mdl" + { + "zho" "煙火" + } + "models/props_interiors/coffee_maker.mdl" + { + "zho" "咖啡機" + } + "models/props_interiors/pot01a.mdl" + { + "zho" "水壺" + } + "models/props_interiors/tv.mdl" + { + "zho" "電視機" + } + "models/props_interiors/lamp_floor_gib2.mdl" + { + "zho" "燈罩1" + } + "models/props_interiors/lamp_table02_gib2.mdl" + { + "zho" "燈罩2" + } + "models/props_lighting/semi_flush_001.mdl" + { + "zho" "燈罩3" + } + "models/props_junk/petfoodbag01.mdl" + { + "zho" "狗糧" + } + "models/props_lighting/flashlight_dropped_01.mdl" + { + "zho" "手電筒" + } + "models/props_lighting/lightfixture03.mdl" + { + "zho" "球燈" + } + "models/props_mall/cash_register.mdl" + { + "zho" "收銀機" + } + "models/props_placeable/tier1_guns_trophy.mdl" + { + "zho" "槍架1" + } + "models/props_placeable/tier2_guns_trophy.mdl" + { + "zho" "槍架2" + } + "models/weapons/arms/v_spitter_arms.mdl" + { + "zho" "Spitter的手" + } + "models/weapons/arms/v_jockey_arms.mdl" + { + "zho" "Jockey的爪" + } + "models/v_models/weapons/v_claw_hulk.mdl" + { + "zho" "Tank的爪" + } + "models/w_models/weapons/w_he_grenade.mdl" + { + "zho" "炮彈" + } + "models/props_junk/propanecanister001a.mdl" + { + "zho" "丙烷氣瓶" + } + "models/w_models/weapons/w_eq_medkit.mdl" + { + "zho" "醫療包帽" + } + "models/weapons/melee/w_riotshield.mdl" + { + "zho" "防暴盾牌" + } + "models/props_skybox/boat_rescue_tug_sunshine.mdl" + { + "zho" "遊艇" + } +} \ No newline at end of file diff --git a/addons/sourcemod/translations/zho/hats.phrases.txt b/addons/sourcemod/translations/zho/hats.phrases.txt new file mode 100644 index 000000000..1e1633552 --- /dev/null +++ b/addons/sourcemod/translations/zho/hats.phrases.txt @@ -0,0 +1,143 @@ +"Phrases" +{ + "Hat_Wearing" + { + "#format" "{1:s}" + "zho" "您正在配戴{ORANGE}{1}{DEFAULT}。" + } + "Hat_Changed" + { + "#format" "{1:s}" + "zho" "您正在配戴{ORANGE}{1}{DEFAULT}。" + } + "Hat_No_Index" + { + "#format" "{1:d}{2:d}" + "zho" "無法找到編號為{ORANGE}{1}{DEFAULT}的帽子。 (應在{ORANGE}1{DEFAULT}至{ORANGE}{2}{DEFAULT}內)" + } + "Hat_Not_Found" + { + "#format" "{1:s}" + "zho" "無法找到帽子{ORANGE}{1}{DEFAULT}。" + } + "Hat_Invalid" + { + "zho" "無效的玩家。" + } + "Hat_Unblocked" + { + "#format" "{1:s}" + "zho" "Unblocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_Blocked" + { + "#format" "{1:s}" + "zho" "Blocked hats for {ORANGE}{1}{DEFAULT}." + } + "Hat_View" + { + "#format" "{1:s}" + "zho" "您已{ORANGE}{1}{DEFAULT}第一人稱可見狀態。" + } + "Hat_Ability" + { + "#format" "{1:s}" + "zho" "您已{ORANGE}{1}{DEFAULT}帽子穿戴功能。" + } + "Hat_On" + { + "zho" "啟用" + } + "Hat_Off" + { + "zho" "停用" + } + "Hat_Menu_Title" + { + "zho" "選擇帽子:" + } + "Hat_Missing" + { + "zho" "無法配戴帽子。" + } + + "HAT_SYSTEM" + { + "zho" "{GREEN}[帽子]{DEFAULT} " + } + "HAT_NOT_RIGHT_NOW" + { + "zho" "暫時無法使用。" + } + "ADMIN_DISABLE_HAT" + { + "zho" "選擇玩家停用帽子:" + } + "ADMIN_CHANGE_HAT" + { + "zho" "選擇玩家更換帽子:" + } + "ADMIN_VISIBILITY" + { + "zho" "Select player to set hat visibility:" + } + "HAT_SET_ANGLE" + { + "zho" "選擇帽子角度:" + } + "HAT_SET_POSITION" + { + "zho" "選擇帽子位置:" + } + "HAT_SET_SIZE" + { + "zho" "選擇帽子大細:" + } + "HAT_MAIN" + { + "zho" "選擇動作:" + } + "HAT_MENU" + { + "zho" "打開帽子選單" + } + "HAT_WORE" + { + "zho" "穿戴狀態" + } + "HAT_VIEWABLE" + { + "zho" "第一人稱可見狀態" + } + "HAT_ENABLED" + { + "zho" "已啟用" + } + "HAT_DISABLED" + { + "zho" "己停用" + } + "HAT_VIEWABLE_TP" + { + "zho" "第三人稱可見狀態" + } + "HAT_VISIBILITY" + { + "zho" "顥示其他玩家的帽子" + } + "Hat_ViewTP" + { + "#format" "{1:s}" + "zho" "您已{ORANGE}{1}{DEFAULT}第三人稱可見狀態" + } + "Hat_ViewSet" + { + "#format" "{1:s}{2:s}" + "zho" "{ORANGE}{2}{DEFAULT}玩家{ORANGE}{1}{DEFAULT}顥示其他玩家的帽子" + } + "Hat_Visibility_Set" + { + "#format" "{1:s}" + "zho" "顯示其他玩家的帽子:{ORANGE}{1}{DEFAULT}" + } +} \ No newline at end of file