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