├── LICENSE ├── README.md ├── csgo ├── aimbot.nut ├── buymenu │ ├── buymenu.nut │ ├── buymenu.vmf │ └── materials │ │ └── ui │ │ ├── buymenu_label_heavy.vmt │ │ ├── buymenu_label_heavy.vtf │ │ ├── buymenu_label_pistol.vmt │ │ ├── buymenu_label_pistol.vtf │ │ ├── buymenu_label_rifle.vmt │ │ ├── buymenu_label_rifle.vtf │ │ ├── buymenu_label_smg.vmt │ │ ├── buymenu_label_smg.vtf │ │ ├── coin.vmt │ │ ├── coin.vtf │ │ ├── coin_exponent.vtf │ │ ├── coin_normal.vtf │ │ ├── cursor.vmt │ │ ├── cursor.vtf │ │ ├── inventory_icon_weapon_ak47.vmt │ │ ├── inventory_icon_weapon_aug.vmt │ │ ├── inventory_icon_weapon_awp.vmt │ │ ├── inventory_icon_weapon_bizon.vmt │ │ ├── inventory_icon_weapon_cz75a.vmt │ │ ├── inventory_icon_weapon_deagle.vmt │ │ ├── inventory_icon_weapon_elite.vmt │ │ ├── inventory_icon_weapon_famas.vmt │ │ ├── inventory_icon_weapon_fiveseven.vmt │ │ ├── inventory_icon_weapon_g3sg1.vmt │ │ ├── inventory_icon_weapon_galilar.vmt │ │ ├── inventory_icon_weapon_glock.vmt │ │ ├── inventory_icon_weapon_hkp2000.vmt │ │ ├── inventory_icon_weapon_m249.vmt │ │ ├── inventory_icon_weapon_m4a1.vmt │ │ ├── inventory_icon_weapon_m4a1_silencer.vmt │ │ ├── inventory_icon_weapon_mac10.vmt │ │ ├── inventory_icon_weapon_mag7.vmt │ │ ├── inventory_icon_weapon_mp5sd.vmt │ │ ├── inventory_icon_weapon_mp7.vmt │ │ ├── inventory_icon_weapon_mp9.vmt │ │ ├── inventory_icon_weapon_negev.vmt │ │ ├── inventory_icon_weapon_nova.vmt │ │ ├── inventory_icon_weapon_p250.vmt │ │ ├── inventory_icon_weapon_p90.vmt │ │ ├── inventory_icon_weapon_revolver.vmt │ │ ├── inventory_icon_weapon_sawedoff.vmt │ │ ├── inventory_icon_weapon_scar20.vmt │ │ ├── inventory_icon_weapon_sg556.vmt │ │ ├── inventory_icon_weapon_ssg08.vmt │ │ ├── inventory_icon_weapon_tec9.vmt │ │ ├── inventory_icon_weapon_ump45.vmt │ │ ├── inventory_icon_weapon_usp_silencer.vmt │ │ ├── inventory_icon_weapon_xm1014.vmt │ │ ├── wedge.vmt │ │ └── wedge.vtf ├── df_gale.nut ├── example-events.nut ├── mazegenerator.nut ├── panel.nut ├── training_sound.nut └── turret.nut ├── hlvr ├── auto_pickup.lua ├── hack_convert.lua └── self_euthanasia.lua ├── left4dead2 └── ping_system.nut └── mapbase ├── boss_swarm ├── baseweapon.nut ├── cursor.nut ├── enemy_bigboss.nut ├── enemy_bigboss_arm.nut ├── hud.nut ├── init.nut ├── item_pickup.nut ├── items.nut ├── map_background.nut ├── object.nut ├── player.nut ├── projectile_simple.nut ├── shield.nut ├── snd.nut ├── swarm.nut ├── weapon_basic.nut ├── weapon_blast.nut ├── weapon_burstgun.nut └── weapon_shotgun.nut ├── cs_hud ├── fonts.nut ├── hud_cs.nut ├── hudammo.nut ├── huddamageindicator.nut ├── hudhealtharmor.nut ├── hudhinttext.nut ├── hudlocator.nut ├── hudpoisondamageindicator.nut ├── hudreticle.nut ├── hudscope.nut ├── hudsquadstatus.nut ├── hudsuit.nut ├── hudweaponselection.nut └── init.nut ├── hud_override.nut ├── keylistener.nut ├── readme.md ├── steam ├── AchievementDisplay.nut ├── AchievementManager.nut ├── AchievementNotification.nut ├── FriendNotification.nut ├── NotificationManager.nut ├── fonts.nut ├── init.nut └── utils.nut ├── tf_hud ├── fonts.nut ├── hud_tf.nut ├── hud_tf_ammo.nut ├── hud_tf_flashlight.nut ├── hud_tf_health.nut ├── hud_tf_playerclass.nut ├── hud_tf_playerstatus.nut ├── hud_tf_scope.nut ├── hud_tf_suitpower.nut ├── hud_tf_weaponselection.nut └── init.nut └── viewmodel_collision.nut /README.md: -------------------------------------------------------------------------------- 1 | # vscripts 2 | Some of my vscript projects. This repository is not always up to date, and it may contain out of date code. 3 | 4 | I do not suggest forking, as I may often rebase small commits. 5 | 6 | ## License 7 | These codes are published in the hope that they will be useful, without any warranty of fitness for a particular purpose. You are free to do whatever you want with them without redistributing them as they are. See [LICENSE](LICENSE) for details. 8 | 9 | [![](http://hits.dwyl.com/samisalreadytaken/vscripts.svg)](https://hits.dwyl.com/samisalreadytaken/vscripts) 10 | 11 | --- 12 | 13 | * [**vs_library**](https://github.com/samisalreadytaken/vs_library) 14 | * [**Notepad++ syntax highlighter**](https://gist.github.com/samisalreadytaken/5bcf322332074f31545ccb6651b88f2d) 15 | -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_heavy.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/buymenu_label_heavy" 4 | "$translucent" 1 5 | 6 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_heavy.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/buymenu_label_heavy.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_pistol.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/buymenu_label_pistol" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_pistol.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/buymenu_label_pistol.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_rifle.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/buymenu_label_rifle" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_rifle.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/buymenu_label_rifle.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_smg.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/buymenu_label_smg" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/buymenu_label_smg.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/buymenu_label_smg.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/coin.vmt: -------------------------------------------------------------------------------- 1 | "vertexlitgeneric" 2 | { 3 | "$basetexture" "ui/coin" 4 | "$bumpmap" "ui/coin_normal" 5 | "$phongexponenttexture" "ui/coin_exponent" 6 | "$envmap" "editor/cube_vertigo" 7 | "$envmapcontrast" "3" 8 | "$envmaptint" "[.04 .04 .04]" 9 | "$envmapfresnel" "1" 10 | "$normalmapalphaenvmapmask" "1" 11 | "$phong" "1" 12 | "$phongboost" "1" 13 | "$phongfresnelranges" "[.7 .8 1]" 14 | "$phongalbedotint" "1" 15 | "$phongalbedoboost" "30" 16 | "$phongdisablehalflambert" "1" 17 | "$translucent" "1" 18 | "$nodecal" "1" 19 | "Proxies" 20 | { 21 | "ToggleTexture" 22 | { 23 | "toggleTextureVar" "$basetexture" 24 | "toggleTextureFrameNumVar" "$frame" 25 | "toggleTextureShouldWrap" "0" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/coin.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/coin.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/coin_exponent.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/coin_exponent.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/coin_normal.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/coin_normal.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/cursor.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/cursor" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/cursor.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/cursor.vtf -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_ak47.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_ak47" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_aug.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_aug" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_awp.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_awp" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_bizon.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_bizon" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_cz75a.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_cz75a" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_deagle.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_deagle" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_elite.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_elite" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_famas.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_famas" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_fiveseven.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_fiveseven" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_g3sg1.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_g3sg1" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_galilar.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_galilar" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_glock.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_glock" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_hkp2000.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_hkp2000" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_m249.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_m249" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_m4a1.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_m4a1" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_m4a1_silencer.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_m4a1_silencer" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_mac10.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_mac10" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_mag7.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_mag7" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_mp5sd.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_mp5sd" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_mp7.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_mp7" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_mp9.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_mp9" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_negev.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_negev" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_nova.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_nova" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_p250.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_p250" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_p90.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_p90" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_revolver.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_revolver" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_sawedoff.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_sawedoff" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_scar20.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_scar20" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_sg556.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_sg556" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_ssg08.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_ssg08" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_tec9.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_tec9" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_ump45.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_ump45" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_usp_silencer.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_usp_silencer" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/inventory_icon_weapon_xm1014.vmt: -------------------------------------------------------------------------------- 1 | "UnlitGeneric" 2 | { 3 | "$basetexture" "icons/inventory_icon_weapon_xm1014" 4 | "$translucent" 1 5 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/wedge.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | "$basetexture" "ui/wedge" 4 | "$alpha" .75 5 | "$translucent" 1 6 | "Proxies" 7 | { 8 | "ToggleTexture" 9 | { 10 | "toggleTextureVar" "$basetexture" 11 | "toggleTextureFrameNumVar" "$frame" 12 | "toggleTextureShouldWrap" "0" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /csgo/buymenu/materials/ui/wedge.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/samisalreadytaken/vscripts/d81c668dde425e460871249030d252c20f692bd8/csgo/buymenu/materials/ui/wedge.vtf -------------------------------------------------------------------------------- /csgo/turret.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | //------------------- Copyright (c) samisalreadytaken ------------------- 3 | // github.com/samisalreadytaken 4 | //- v0.5.4 -------------------------------------------------------------- 5 | // 6 | // Player controlled turret (multiplayer compatible) 7 | // 8 | // Required entities (targetnames are arbitrary): 9 | // 10 | // prop_dynamic: (gun model prop) 11 | // targetname: turret_gun_0 12 | // model: models/weapons/w_mach_m249.mdl 13 | // 14 | // env_gunfire: (fire origin, place in front of the gun barrel) 15 | // targetname: turret_fire_0 16 | // parentname: turret_gun_0 (gun model prop) 17 | // target: turret_target_0 (aim target) 18 | // weaponname: weapon_p90 (determines the damage) 19 | // StartDisabled: 1 20 | // maxburstdelay: 0 21 | // minburstdelay: 0 22 | // 23 | // info_target: (aim target, placement does not matter) 24 | // targetname: turret_target_0 25 | // 26 | // func_button: (to use the turret) 27 | // OnPressed > !activator > RunScriptCode > ::TURRET.Use( #YOUR_TURRET_VAR# ) 28 | // 29 | // Create your turret in your script 30 | // 31 | // #YOUR_TURRET_VAR# <- ::TURRET.Create( "turret_gun_0", "turret_fire_0", "turret_target_0" ); 32 | // 33 | // Disable on round start to make sure there are no players left using the 34 | // turret from the previous round 35 | // VS.ListenToGameEvent( "round_start", function(ev) 36 | // { 37 | // ::TURRET.Disable( #YOUR_TURRET_VAR# ) 38 | // }, "TurretDisable" ); 39 | // 40 | // 41 | // Crosshair overlay and sounds can also be set exclusively for each turret 42 | // 43 | // hTurret2 <- ::TURRET.Create( "turret_gun_2", 44 | // "turret_fire_2", 45 | // "turret_target_2", 46 | // "mymap/overlay", 47 | // "Weapon_M249.Pump", 48 | // "Weapon_AK47.Single" ); 49 | // 50 | 51 | // option defaults 52 | local SND_USE = "Weapon_M249.Pump"; 53 | local SND_FIRE = "Weapon_M249.Single"; 54 | local TURRET_USE_OVERLAY = ""; 55 | 56 | IncludeScript("vs_library"); 57 | 58 | if ( !("g_TurretList" in getroottable()) ) 59 | ::g_TurretList <- {};; 60 | 61 | if ( !("g_pClientCommand" in getroottable()) ) 62 | ::g_pClientCommand <- VS.CreateEntity( "point_clientcommand", null, true );; 63 | 64 | if ( !("TURRET" in getroottable()) ) 65 | ::TURRET <- {} 66 | 67 | else return;; 68 | 69 | 70 | function TURRET::Create( 71 | szNameGunMDL, 72 | szNameGunFire, 73 | szNameGunTarget, 74 | szOverlayOn = TURRET_USE_OVERLAY, 75 | szSndUse = SND_USE, 76 | szSndFire = SND_FIRE 77 | ) 78 | { 79 | local hGunProp = ::Ent(szNameGunMDL); 80 | local hGunFire = ::Ent(szNameGunFire); 81 | local hTarget = ::Ent(szNameGunTarget); 82 | 83 | if ( !hGunProp || !hTarget || !hGunFire ) 84 | return Msg("TURRET: could not find entities\n"); 85 | 86 | local hCtrl; 87 | 88 | foreach( k,v in g_TurretList ) 89 | { 90 | if ( k.IsValid() && (k.GetScriptScope().m_hGunProp.GetName() == szNameGunMDL) ) 91 | { 92 | hCtrl = k; 93 | break; 94 | }; 95 | } 96 | 97 | if ( !hCtrl ) 98 | { 99 | hCtrl = ::VS.CreateEntity( "game_ui",{ spawnflags = (1<<5)|(1<<6)|(1<<7), fieldofview = -1.0 },true ); 100 | 101 | g_TurretList[hCtrl] <- 102 | { 103 | szSndFire = szSndFire, 104 | szSndUse = szSndUse, 105 | szOverlayOn = szOverlayOn, 106 | szNameGunMDL = szNameGunMDL, 107 | szNameGunFire = szNameGunFire, 108 | szNameGunTarget = szNameGunTarget 109 | } 110 | }; 111 | 112 | Reset(hCtrl); 113 | 114 | return hCtrl; 115 | } 116 | 117 | function TURRET::Reset( hCtrl ) : (g_TurretList) 118 | { 119 | hCtrl.ValidateScriptScope(); 120 | local sc = hCtrl.GetScriptScope(); 121 | local ls = g_TurretList[hCtrl]; 122 | 123 | local hGunProp = ::Ent( ls.szNameGunMDL ); 124 | local hGunFire = ::Ent( ls.szNameGunFire ); 125 | local hTarget = ::Ent( ls.szNameGunTarget ); 126 | 127 | sc.m_bShooting <- false; 128 | sc.m_hUser <- null; 129 | sc.m_hGunProp <- hGunProp.weakref(); 130 | sc.m_hGunFire <- hGunFire.weakref(); 131 | sc.m_hTarget <- hTarget.weakref(); 132 | sc.m_szOverlayOn <- ls.szOverlayOn; 133 | sc.m_szSndFire <- ls.szSndFire; 134 | sc.m_szSndUse <- ls.szSndUse; 135 | 136 | AddOutputs( hCtrl ); 137 | } 138 | 139 | function TURRET::Disable( hCtrl, bForceDeactivate = true ) : (g_pClientCommand) 140 | { 141 | local sc = hCtrl.GetScriptScope(); 142 | 143 | if ( sc.m_hUser && sc.m_hUser.IsValid() ) 144 | { 145 | // +use already deactivates itself (spawnflag 7) 146 | // but this is required if the player did not deactivate, but was killed or round ended 147 | if ( bForceDeactivate ) 148 | ::DoEntFireByInstanceHandle( hCtrl, "Deactivate", "", 0, sc.m_hUser.self, null ); 149 | 150 | ::DoEntFireByInstanceHandle( g_pClientCommand, "Command", "r_screenoverlay\"\"", 0, sc.m_hUser.self, null ); 151 | }; 152 | 153 | if ( sc.m_hGunFire ) 154 | ::EntFireByHandle( sc.m_hGunFire, "Disable" ); 155 | 156 | sc.m_bShooting = false; 157 | sc.m_hUser = null; 158 | } 159 | 160 | function TURRET::Use( hCtrl, ply = null ) 161 | { 162 | if ( !ply ) 163 | { 164 | if ( "activator" in ::getroottable() ) 165 | { 166 | ply = ::activator; 167 | } 168 | else 169 | { 170 | return Msg("TURRET: could not find player to use\n"); 171 | }; 172 | }; 173 | 174 | local sc = hCtrl.GetScriptScope(); 175 | 176 | // this block will not be called because +use already disables the turret (spawnflag 7) 177 | if ( sc.m_hUser ) 178 | { 179 | if ( sc.m_hUser.self == ply ) 180 | { 181 | Msg("TURRET: unexpected execution!\n"); 182 | DoEntFireByInstanceHandle( sc.self, "Deactivate", "", 0, ply, null ); 183 | return; 184 | } 185 | else if ( sc.m_hUser.IsValid() ) 186 | { 187 | return Msg("TURRET: Someone tried to use the turret while it was already in use\n"); 188 | };; 189 | }; 190 | 191 | if ( ply && ply.IsValid() && ply.GetClassname() == "player" ) 192 | { 193 | // round restart, gunfire and prop are respawned, previous references are invalid 194 | if ( !sc.m_hGunFire ) 195 | { 196 | Reset(hCtrl); 197 | }; 198 | 199 | ::DoEntFireByInstanceHandle( sc.self, "Activate", "", 0, ply, null ); 200 | 201 | // local scPlayer = ply.GetScriptScope(); 202 | // if( scPlayer ) 203 | // { 204 | // scPlayer.hControlledTurret <- sc.self.weakref(); 205 | // }; 206 | }; 207 | } 208 | 209 | // internal functions -------------------------------------- 210 | 211 | function TURRET::OnUse() : (g_pClientCommand) 212 | { 213 | m_hUser = ToExtendedPlayer( ::activator ); 214 | m_bShooting = false; 215 | 216 | ::EntFireByHandle( m_hGunFire, "Disable" ); 217 | ::DoEntFireByInstanceHandle( g_pClientCommand, 218 | "Command", 219 | "r_screenoverlay\""+m_szOverlayOn+"\"", 220 | 0, m_hUser.self, null ); 221 | 222 | m_hGunProp.EmitSound( m_szSndUse ); 223 | 224 | // start thinking 225 | Think(); 226 | } 227 | 228 | function TURRET::OnAttackPressed() 229 | { 230 | ::EntFireByHandle( m_hGunFire, "Enable" ); 231 | m_bShooting = true; 232 | } 233 | 234 | function TURRET::OnAttackRelease() 235 | { 236 | ::EntFireByHandle( m_hGunFire, "Disable" ); 237 | m_bShooting = false; 238 | } 239 | 240 | function TURRET::Think() 241 | { 242 | if ( !m_hUser || !m_hUser.IsValid() ) 243 | return; 244 | 245 | if ( !m_hUser.GetHealth() ) 246 | return ::TURRET.Disable(self); 247 | 248 | // if( m_nFireCount ++>= m_nCooldownLimit ) 249 | // { 250 | // return VS.EventQueue.AddEvent( Think, m_flRecoverTime, this ); 251 | // }; 252 | 253 | local vecTargetPos = VS.TraceDir( 254 | m_hUser.EyePosition(), 255 | m_hUser.EyeForward(), 256 | MAX_TRACE_LENGTH, 257 | m_hUser.self, 258 | MASK_SOLID ).GetPos(); 259 | 260 | m_hTarget.SetOrigin( vecTargetPos ); 261 | m_hGunProp.SetForwardVector( vecTargetPos - m_hGunProp.GetOrigin() ); 262 | 263 | if ( m_bShooting ) 264 | { 265 | m_hGunProp.EmitSound(m_szSndFire); 266 | }; 267 | 268 | return VS.EventQueue.AddEvent( Think, 0.05, this ); 269 | } 270 | 271 | function TURRET::AddOutputs( hCtrl ) 272 | { 273 | local sc = hCtrl.GetScriptScope(); 274 | VS.AddOutput( hCtrl, "PressedAttack", OnAttackPressed, sc ); 275 | VS.AddOutput( hCtrl, "UnpressedAttack", OnAttackRelease, sc ); 276 | VS.AddOutput( hCtrl, "PlayerOn", OnUse, sc ); 277 | VS.AddOutput( hCtrl, "PlayerOff", function(){ return ::TURRET.Disable( self, false ) }, sc ); 278 | sc.Think <- Think.bindenv( sc ); 279 | } 280 | 281 | -------------------------------------------------------------------------------- /hlvr/self_euthanasia.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------- 2 | -- github.com/samisalreadytaken 3 | -- self euthanasia 4 | ------------------------------------------------------------------------- 5 | 6 | if CLIENT_DLL then 7 | return 8 | end 9 | 10 | -- from vs_math 11 | local IsBoxIntersectingRay = function( boxMin, boxMax, origin, vecDelta ) 12 | 13 | local tmin, tmax, EPS = 1.175494351e-38, 3.402823466e+38, 1.e-8; 14 | 15 | if ( vecDelta.x < EPS and vecDelta.x > -EPS ) then 16 | if ( (origin.x < boxMin.x) or (origin.x > boxMax.x) ) then 17 | return false; 18 | end 19 | else 20 | local invDelta = 1.0 / vecDelta.x; 21 | local t1 = (boxMin.x - origin.x) * invDelta; 22 | local t2 = (boxMax.x - origin.x) * invDelta; 23 | if ( t1 > t2 ) then 24 | local tmp = t1; 25 | t1 = t2; 26 | t2 = tmp; 27 | end 28 | if (t1 > tmin) then 29 | tmin = t1; 30 | end 31 | if (t2 < tmax) then 32 | tmax = t2; 33 | end 34 | if (tmin > tmax) then 35 | return false; 36 | end 37 | if (tmax < 0.0) then 38 | return false; 39 | end 40 | if (tmin > 1.0) then 41 | return false; 42 | end 43 | end 44 | 45 | if ( vecDelta.y < EPS and vecDelta.y > -EPS ) then 46 | if ( (origin.y < boxMin.y) or (origin.y > boxMax.y) ) then 47 | return false; 48 | end 49 | else 50 | local invDelta = 1.0 / vecDelta.y; 51 | local t1 = (boxMin.y - origin.y) * invDelta; 52 | local t2 = (boxMax.y - origin.y) * invDelta; 53 | if ( t1 > t2 ) then 54 | local tmp = t1; 55 | t1 = t2; 56 | t2 = tmp; 57 | end 58 | if (t1 > tmin) then 59 | tmin = t1; 60 | end 61 | if (t2 < tmax) then 62 | tmax = t2; 63 | end 64 | if (tmin > tmax) then 65 | return false; 66 | end 67 | if (tmax < 0.0) then 68 | return false; 69 | end 70 | if (tmin > 1.0) then 71 | return false; 72 | end 73 | end 74 | 75 | if ( vecDelta.z < EPS and vecDelta.z > -EPS ) then 76 | if ( (origin.z < boxMin.z) or (origin.z > boxMax.z) ) then 77 | return false; 78 | end 79 | else 80 | local invDelta = 1.0 / vecDelta.z; 81 | local t1 = (boxMin.z - origin.z) * invDelta; 82 | local t2 = (boxMax.z - origin.z) * invDelta; 83 | if ( t1 > t2 ) then 84 | local tmp = t1; 85 | t1 = t2; 86 | t2 = tmp; 87 | end 88 | if (t1 > tmin) then 89 | tmin = t1; 90 | end 91 | if (t2 < tmax) then 92 | tmax = t2; 93 | end 94 | if (tmin > tmax) then 95 | return false; 96 | end 97 | if (tmax < 0.0) then 98 | return false; 99 | end 100 | if (tmin > 1.0) then 101 | return false; 102 | end 103 | end 104 | 105 | return true; 106 | end 107 | 108 | -------------------------------- 109 | 110 | if g_iSEFireEvent then 111 | StopListeningToGameEvent( g_iSEFireEvent ) 112 | g_iSEFireEvent = nil 113 | end 114 | 115 | local Entities, CreateDamageInfo, DestroyDamageInfo = Entities, CreateDamageInfo, DestroyDamageInfo 116 | 117 | local m_hPlayer, m_HMDAvatar 118 | local m_vecAvatarMins, m_vecAvatarMaxs 119 | 120 | g_iSEFireEvent = ListenToGameEvent( "player_shoot_weapon", function() 121 | 122 | local pos = m_hPlayer:ShootPosition( 0, 1 ) 123 | local wep = Entities:FindByClassnameWithin( nil, "hlvr_weapon*", pos, 0.5 ) 124 | if wep then 125 | 126 | local iAttachment = wep:ScriptLookupAttachment( "muzzle" ) 127 | if iAttachment > -1 then 128 | 129 | local dt = wep:GetAttachmentForward( iAttachment ) * 128.0 130 | local org = m_HMDAvatar:GetOrigin() 131 | 132 | if IsBoxIntersectingRay( org + m_vecAvatarMins, org + m_vecAvatarMaxs, pos, dt ) then 133 | 134 | if wep:GetClassname() == "hlvr_weapon_rapidfire" then -- ??? 135 | SendToConsole("kill") 136 | else 137 | local info = CreateDamageInfo( wep, m_hPlayer, dt, pos, 1.e+30, 2 ) 138 | m_hPlayer:TakeDamage( info ) 139 | DestroyDamageInfo( info ) 140 | end 141 | 142 | print("bang") 143 | 144 | end 145 | 146 | end 147 | 148 | end 149 | 150 | end, nil ) 151 | 152 | local Init = function() 153 | 154 | m_hPlayer = Entities:GetLocalPlayer() 155 | 156 | if m_hPlayer then 157 | 158 | m_HMDAvatar = m_hPlayer:GetHMDAvatar() 159 | 160 | if m_HMDAvatar then 161 | 162 | m_vecAvatarMins = m_HMDAvatar:GetBoundingMins() 163 | m_vecAvatarMaxs = m_HMDAvatar:GetBoundingMaxs() 164 | 165 | Msg("Loaded self_euthanasia\n") 166 | 167 | return true 168 | 169 | end 170 | 171 | end 172 | 173 | return false 174 | 175 | end 176 | 177 | local VS = require "vs_library-013" 178 | 179 | if not VS.OnPlayerSpawn( Init, "self_euthanasia: could not find player" ) then 180 | Init() 181 | end 182 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/baseweapon.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( "CBaseWeapon" in this ) 6 | return; 7 | 8 | local Swarm = this; 9 | local Time = Time, NetMsg = NetMsg; 10 | 11 | class CBaseWeapon extends CItem 12 | { 13 | m_flProjectileSpeed = 0.0; 14 | m_flRefireTime = 0.0; 15 | m_nClip = 0; 16 | m_nAmmo = -1; 17 | m_nMaxClip = 0; 18 | m_flReloadTime = 1.0; 19 | 20 | m_nPenetration = 1; 21 | m_nDamage = 1; 22 | 23 | m_vecShootPosition = null; 24 | m_flNextAttackTime = 0.0; 25 | m_bInReload = false; 26 | m_szSoundReload = ""; 27 | m_szSoundReloadEnd = ""; 28 | 29 | m_Modifiers = 0; 30 | 31 | constructor( owner ) 32 | { 33 | m_hOwner = owner; 34 | m_nTeam = owner.m_nTeam; 35 | } 36 | 37 | Attack = dummy; 38 | } 39 | 40 | function CBaseWeapon::CheckReload() 41 | { 42 | //Assert( m_bInReload ); 43 | 44 | local curtime = Time(); 45 | if ( curtime < m_flNextAttackTime ) 46 | return; 47 | 48 | m_bInReload = false; 49 | 50 | m_flNextAttackTime = curtime; 51 | 52 | if ( m_nAmmo != -1 ) 53 | { 54 | local clip = min( m_nMaxClip - m_nClip, m_nAmmo ); 55 | m_nAmmo -= m_nClip = clip; 56 | } 57 | else 58 | { 59 | m_nClip = m_nMaxClip; 60 | } 61 | 62 | return Swarm.PlaySound( SwarmSound.PlayerWeapon, m_szSoundReloadEnd ); 63 | } 64 | 65 | function CBaseWeapon::Reload() 66 | { 67 | //Assert( !m_bInReload ); 68 | 69 | m_bInReload = true; 70 | local curtime = Time(); 71 | m_flNextAttackTime = curtime + m_flReloadTime; 72 | 73 | NetMsg.Start( "Swarm.CPlayer.Reload" ); 74 | NetMsg.WriteByte( m_iSlot ); 75 | NetMsg.WriteFloat( m_flReloadTime ); 76 | NetMsg.Send( m_hOwner.m_pBasePlayer, true ); 77 | 78 | return Swarm.PlaySound( SwarmSound.PlayerWeapon, m_szSoundReload ); 79 | } 80 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/enemy_bigboss.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | 6 | enum ArmAttack 7 | { 8 | None, 9 | Type1, 10 | Type2, 11 | Type3, 12 | } 13 | 14 | IncludeScript( "boss_swarm/projectile_simple.nut", this ); 15 | IncludeScript( "boss_swarm/shield.nut", this ); 16 | IncludeScript( "boss_swarm/enemy_bigboss_arm.nut", this ); 17 | 18 | local Swarm = this; 19 | local Time = Time, NetMsg = NetMsg, RandomFloat = RandomFloat; 20 | 21 | PrecacheModel( "swarm/boss1.vmt" ); 22 | 23 | local SUB_RestoreColour = function( ent ) 24 | { 25 | if ( ent ) 26 | ent.SetRenderColor( 255, 0, 0 ); 27 | } 28 | 29 | class CBigBoss extends CEntity 30 | { 31 | CBossArm = CBossArm; 32 | CShield = CShield; 33 | 34 | m_nHealth = 500; 35 | m_flTotalHealth = 0.0; 36 | m_flTotalShield = 0.0; 37 | m_flCurHealth = 0.0; 38 | m_flCurShield = 0.0; 39 | 40 | m_nTeam = 2; 41 | 42 | m_flRotation = 0.0; 43 | 44 | m_pShieldRotator = null; 45 | 46 | m_Shields = null; 47 | m_Arms = null; 48 | m_nArmCount = 0; 49 | 50 | m_attack = 0; 51 | m_stage = 0; 52 | m_fnAttack = null; 53 | } 54 | 55 | function CBigBoss::constructor( position ) 56 | { 57 | base.constructor(); 58 | 59 | Swarm.m_HurtableEntities.append( this ); 60 | 61 | m_Shields = []; 62 | m_Arms = []; 63 | 64 | position.z = 0.0; 65 | m_vecPosition.Copy( position ); 66 | m_vecHullMins.Init( -50, -50, 0 ); 67 | m_vecHullMaxs.Init( 50, 50, 4 ); 68 | 69 | m_pEntity = Swarm.SpriteCreate( "swarm/boss1.vmt", 0.9, 70 | MOVETYPE_FLY, position, vec3_origin, 71 | m_vecHullMins, m_vecHullMaxs ); 72 | 73 | m_pEntity.SetSolid( 2 ); 74 | m_pEntity.RemoveSolidFlags( FSOLID_NOT_SOLID ); 75 | m_pEntity.SetRenderColor( 255, 0, 0 ); 76 | 77 | m_pShieldRotator = Entities.CreateByClassname( "info_null" ); 78 | //m_pShieldRotator.SetParent( m_pEntity, "" ); 79 | m_pShieldRotator.SetLocalOrigin( position ); 80 | m_pShieldRotator.SetLocalAngles( vec3_origin ); 81 | m_pShieldRotator.SetMoveType( MOVETYPE_NOCLIP ); 82 | 83 | for ( local ang = 0.0; ang < 360.0; ang += 30.0 ) 84 | { 85 | local dir = VS.VectorYawRotate( m_vecForward, ang ); 86 | local obj = CShield( this, m_pShieldRotator, position + dir * 70, dir ); 87 | m_Shields.append( obj ); 88 | m_flTotalShield += obj.m_nHealth.tofloat(); 89 | } 90 | 91 | local i = -1; 92 | for ( local ang = 0.0; ang < 360.0; ang += 45.0 ) 93 | { 94 | local dir = VS.VectorYawRotate( m_vecForward, ang ); 95 | local obj = CBossArm( this, position + dir * 70, dir ); 96 | m_Arms.append( obj ); 97 | obj.m_index = ++i; 98 | m_flTotalHealth += obj.m_nHealth.tofloat(); 99 | } 100 | 101 | m_flTotalHealth += m_nHealth; 102 | } 103 | 104 | function CBigBoss::UpdateHealthStats() 105 | { 106 | local curHealth = m_nHealth, curShield = 0.0; 107 | 108 | foreach( v in m_Arms ) 109 | { 110 | curHealth += v.m_nHealth; 111 | } 112 | 113 | foreach( v in m_Shields ) 114 | { 115 | curShield += v.m_nHealth; 116 | } 117 | 118 | m_flCurHealth = curHealth; 119 | m_flCurShield = curShield; 120 | } 121 | 122 | function CBigBoss::Spawn() 123 | { 124 | base.Spawn(); 125 | 126 | m_flRotation = 360.0 * 0.1 * TICK_INTERVAL; 127 | m_attack = 0; 128 | m_stage = 0; 129 | 130 | m_pEntity.SetContextThink( "AttackThink", AttackThink.bindenv(this), 0.0 ); 131 | UpdateHealthStats(); 132 | } 133 | 134 | function CBigBoss::Destroy( bKilledByPlayer = false ) 135 | { 136 | local x = Swarm.m_HurtableEntities.find( this ); 137 | if ( x != null ) 138 | Swarm.m_HurtableEntities.remove( x ); 139 | 140 | foreach ( obj in m_Shields ) 141 | { 142 | if ( obj.m_nHealth > 0 ) 143 | obj.Destroy(); 144 | } 145 | 146 | foreach ( obj in m_Arms ) 147 | { 148 | if ( obj.m_nHealth > 0 ) 149 | obj.Destroy(); 150 | } 151 | 152 | m_Shields.clear(); 153 | m_Arms.clear(); 154 | 155 | if ( bKilledByPlayer && Swarm.m_Players[0].m_nHealth > 0 ) 156 | { 157 | local basePlayer = Swarm.m_Players[0].m_pBasePlayer; 158 | SteamAchievements.IncrementStat( basePlayer, "STAT_BEAT_BIGBOSS", 1 ); 159 | 160 | printf( "STAT_BEAT_BIGBOSS = %d\n", SteamAchievements.GetStat( basePlayer, "STAT_BEAT_BIGBOSS" ) ); 161 | 162 | NetMsg.Start( "Swarm.CBigBoss.Dead" ); 163 | NetMsg.Send( basePlayer, true ); 164 | } 165 | 166 | Swarm.m_hBigBoss = null; 167 | 168 | m_pEntity.SetContextThink( "", null, 0.0 ); 169 | return m_pEntity.Destroy(); 170 | } 171 | 172 | // Hacks all around, no time left for proper solutions 173 | function CBigBoss::Attack1() 174 | { 175 | local restTime = 1.0; 176 | local curtime = Time() + restTime; 177 | local sw = RandomInt( 0, 1 ); 178 | 179 | foreach ( i, arm in m_Arms ) 180 | { 181 | arm.m_flRefireTime = 0.25; 182 | arm.m_nCurAttack = ArmAttack.Type1; 183 | 184 | if ( (i & 1)^sw ) 185 | { 186 | arm.m_flNextAttackTime = curtime; 187 | } 188 | else 189 | { 190 | arm.m_flNextAttackTime = curtime + arm.m_flRefireTime * 0.5; 191 | } 192 | } 193 | 194 | if ( RandomInt( 0, 1 ) ) 195 | { 196 | m_flRotation = 360.0 * 0.5 * TICK_INTERVAL; 197 | } 198 | else 199 | { 200 | m_flRotation = -360.0 * 0.5 * TICK_INTERVAL; 201 | } 202 | 203 | return RandomFloat( 5.0, 8.0 ); 204 | } 205 | 206 | function CBigBoss::Attack2() 207 | { 208 | local restTime = 1.5; 209 | local curtime = Time() + restTime; 210 | 211 | foreach ( i, arm in m_Arms ) 212 | { 213 | arm.m_flRefireTime = 0.1; 214 | arm.m_nCurAttack = ArmAttack.Type2; 215 | arm.m_flNextAttackTime = curtime; 216 | } 217 | 218 | if ( RandomInt( 0, 1 ) ) 219 | { 220 | m_flRotation = 360.0 * 0.25 * TICK_INTERVAL; 221 | } 222 | else 223 | { 224 | m_flRotation = -360.0 * 0.25 * TICK_INTERVAL; 225 | } 226 | 227 | return RandomFloat( 5.0, 8.0 ); 228 | } 229 | 230 | function CBigBoss::Attack3() 231 | { 232 | local switchTime = 0.75; 233 | 234 | switch ( m_stage ) 235 | { 236 | case 0: 237 | { 238 | local restTime = 0.75; 239 | local curtime = Time() + restTime; 240 | local sw = RandomInt( 0, 1 ); 241 | 242 | foreach ( i, arm in m_Arms ) 243 | { 244 | if ( (i & 1)^sw ) 245 | { 246 | arm.m_nCurAttack = ArmAttack.Type3; 247 | arm.m_flRefireTime = TICK_INTERVAL; 248 | arm.m_flNextAttackTime = curtime; 249 | } 250 | else 251 | { 252 | arm.m_nCurAttack = ArmAttack.None; 253 | } 254 | } 255 | 256 | // Any less than 65% will leave gaps in between the projectiles where the player can sit still 257 | if ( RandomInt( 0, 1 ) ) 258 | { 259 | m_flRotation = 360.0 * 0.65 * TICK_INTERVAL; 260 | } 261 | else 262 | { 263 | m_flRotation = -360.0 * 0.65 * TICK_INTERVAL; 264 | } 265 | 266 | ++m_stage; 267 | m_fnAttack = Attack3; 268 | 269 | return restTime + switchTime * 0.25; 270 | } 271 | 272 | // Final swing 273 | case 12: 274 | m_stage = 0; 275 | m_attack = 0; 276 | return switchTime; 277 | 278 | // Rotation change 279 | default: 280 | m_flRotation = -m_flRotation; 281 | ++m_stage; 282 | return switchTime; 283 | } 284 | } 285 | 286 | function CBigBoss::ChooseRandomAttack() 287 | { 288 | const BOSS_ATTACK_COUNT = 3; 289 | 290 | local i = RandomInt( 1, BOSS_ATTACK_COUNT ); 291 | return this["Attack"+i](); 292 | } 293 | 294 | function CBigBoss::AttackThink( m_pEntity ) 295 | { 296 | if ( m_stage ) 297 | return m_fnAttack(); 298 | 299 | return ChooseRandomAttack(); 300 | } 301 | 302 | function CBigBoss::Frame( m_pEntity ) 303 | { 304 | if ( m_flRotation ) 305 | RotateByAngle( m_flRotation ); 306 | 307 | m_pShieldRotator.SetLocalOrigin( m_vecPosition ); 308 | RotateBaseEntityByAngle( m_pShieldRotator, -3.0 ); 309 | 310 | // NOTE: If there are no shields, (0 div 0 = -nan) will write 1 to the net msg 311 | NetMsg.Start( "Swarm.CBigBoss.Update" ); 312 | NetMsg.WriteNormal( m_flCurHealth / m_flTotalHealth ); 313 | NetMsg.WriteNormal( m_flCurShield / m_flTotalShield ); 314 | NetMsg.Send( Swarm.m_Players[0].m_pBasePlayer, true ); 315 | 316 | DebugDrawBBox(); 317 | 318 | return 0.0; 319 | } 320 | 321 | function CBigBoss::TakeProjectileDamage( projectile ) 322 | { 323 | local damage = projectile.m_nDamage; 324 | // TODO: Take x10 damage until independent weapons are added to the boss 325 | if ( !m_nArmCount ) 326 | { 327 | damage *= 10; 328 | } 329 | 330 | m_nHealth -= damage; 331 | 332 | if ( m_nHealth < 0 ) 333 | m_nHealth = 0; 334 | 335 | UpdateHealthStats(); 336 | 337 | m_pEntity.SetRenderColor( 255, 255, 255 ); 338 | m_pEntity.SetContextThink( "RestoreColour", SUB_RestoreColour, 0.2 ); 339 | 340 | if ( m_nHealth == 0 ) 341 | { 342 | Destroy( true ); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/enemy_bigboss_arm.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( "CBossArm" in this ) 6 | return; 7 | 8 | local Swarm = this; 9 | local Time = Time, RandomFloat = RandomFloat; 10 | 11 | local SND_FIRE = "GenericNPC.GunSound"; 12 | local SND_FIRE2 = "GenericNPC.GunSound"; 13 | local SND_FIRE3 = "Grenade.Blip"; 14 | 15 | PrecacheSoundScript( SND_FIRE ); 16 | PrecacheSoundScript( SND_FIRE2 ); 17 | PrecacheSoundScript( SND_FIRE3 ); 18 | 19 | 20 | local CProjectile = class extends CSimpleProjectile 21 | { 22 | m_flLifeTime = 10.0; 23 | } 24 | 25 | PrecacheModel( "swarm/bossarm.vmt" ); 26 | 27 | local SUB_RestoreColour = function( ent ) 28 | { 29 | if ( ent ) 30 | ent.SetRenderColor( 255, 120, 0 ); 31 | } 32 | 33 | class CBossArm extends CEntity 34 | { 35 | m_index = -1; 36 | m_nTeam = 2; 37 | 38 | m_nHealth = 100; 39 | 40 | m_hOwner = null; 41 | m_bIdle = false; 42 | m_nCurAttack = 0; 43 | m_flNextAttackTime = 0.0; 44 | m_flRefireTime = 0.0; 45 | m_flProjectileSpeed = 180.0; 46 | 47 | // CBaseWeapon (for CSimpleProjectile) 48 | m_nPenetration = 1; 49 | m_nDamage = 1; 50 | } 51 | 52 | // 53 | // NOTE: Using game's parenting instead of keeping track of own transforms 54 | // so that all arms can be easily rotated at once by rotating the parent. 55 | // 56 | function CBossArm::constructor( hParent, position, forward ) 57 | { 58 | base.constructor(); 59 | 60 | m_hOwner = hParent; 61 | ++m_hOwner.m_nArmCount; 62 | 63 | Swarm.m_HurtableEntities.append( this ); 64 | 65 | position.z = 0.0; 66 | m_vecPosition.Copy( position ); 67 | m_vecHullMins.Init( -16, -16, 0 ); 68 | m_vecHullMaxs.Init( 16, 16, 4 ); 69 | 70 | m_pEntity = Swarm.SpriteCreate( "swarm/bossarm.vmt", 0.5, 71 | MOVETYPE_NONE, position, vec3_origin, 72 | m_vecHullMins, m_vecHullMaxs ); 73 | 74 | m_pEntity.SetRenderColor( 255, 120, 0 ); 75 | 76 | SetForward( forward ); 77 | SetParent( hParent.m_pEntity ); 78 | 79 | return Spawn(); 80 | } 81 | 82 | function CBossArm::Destroy() 83 | { 84 | --m_hOwner.m_nArmCount; 85 | local x = Swarm.m_HurtableEntities.find( this ); 86 | if ( x != null ) 87 | Swarm.m_HurtableEntities.remove( x ); 88 | m_pEntity.SetContextThink( "", null, 0.0 ); 89 | return m_pEntity.Destroy(); 90 | } 91 | 92 | local sqrt = sqrt; 93 | 94 | class CHomingProjectile extends CSimpleProjectile 95 | { 96 | m_flLifeTime = 2.5; 97 | 98 | constructor( ownerWeapon, position, velocity ) 99 | { 100 | base.constructor( ownerWeapon, position, velocity ); 101 | m_pEntity.SetContextThink( "Nudge", NudgeThink.bindenv(this), 0.0 ); 102 | 103 | m_flInitVel = sqrt(m_flInitVel); 104 | } 105 | 106 | function Destroy() 107 | { 108 | m_pEntity.SetContextThink( "Nudge", null, 0.0 ); 109 | return base.Destroy(); 110 | } 111 | 112 | function NudgeThink( m_pEntity ) 113 | { 114 | local vecTarget = Swarm.m_Players[0].m_vecPosition; 115 | local vecDelta = vecTarget - m_vecPosition; 116 | 117 | local vel = m_pEntity.GetVelocity(); 118 | local dot = vel.Dot( vecDelta ); 119 | vecDelta.Norm(); 120 | vel.Norm(); 121 | vel.Add( vecDelta.Multiply( 0.75 ) ); 122 | vel.Multiply( m_flInitVel ); 123 | m_pEntity.SetVelocity( vel ); 124 | 125 | return 0.15; 126 | } 127 | 128 | // Copied from CSimpleProjectile with velocity check removed so the weapons 129 | // on the opposite side to the player can shoot as well. 130 | // Life time is relied on to kill these projectiles 131 | function Frame( m_pEntity ) 132 | { 133 | local pos = m_pEntity.GetLocalOrigin(); 134 | local radius = m_flRadius; 135 | local penetration = m_iMaxHits; 136 | local team = m_nTeam; 137 | 138 | foreach ( obj in Swarm.m_HurtableEntities ) 139 | { 140 | if ( ( obj.m_nTeam != team ) && 141 | ( obj.m_vecPosition.DistTo( pos ) < (radius+obj.m_vecHullMaxs.x) ) && 142 | ( ( penetration == 1 ) || (m_PreviousHits.find(obj) == null) ) ) 143 | { 144 | obj.TakeProjectileDamage( this ); 145 | 146 | m_PreviousHits[m_iHits] = obj; 147 | 148 | if ( ++m_iHits >= penetration ) 149 | { 150 | Destroy(); 151 | return -1; 152 | } 153 | } 154 | } 155 | 156 | m_vecPosition.Copy( pos ); 157 | 158 | return 0.0; 159 | } 160 | } 161 | 162 | local CHomingProjectile = CHomingProjectile; 163 | 164 | function CBossArm::Frame( m_pEntity ) 165 | { 166 | m_vecPosition.Copy( m_pEntity.GetOrigin() ); 167 | 168 | if ( m_bIdle ) 169 | return 0.0; 170 | 171 | local curtime = Time(); 172 | 173 | switch ( m_nCurAttack ) 174 | { 175 | // Basic 176 | case ArmAttack.Type1: 177 | { 178 | if ( m_flNextAttackTime <= curtime ) 179 | { 180 | m_flNextAttackTime = curtime + m_flRefireTime; 181 | 182 | local attackDir = m_pEntity.GetUpVector(); 183 | attackDir.Multiply( m_flProjectileSpeed ); 184 | 185 | local shootPos = m_vecPosition; 186 | CProjectile( this, shootPos, attackDir ); 187 | Swarm.PlaySound( SwarmSound.BossWeapon, SND_FIRE ); 188 | } 189 | break; 190 | } 191 | // Homing projectiles 192 | case ArmAttack.Type2: 193 | { 194 | if ( m_flNextAttackTime <= curtime ) 195 | { 196 | m_flNextAttackTime = curtime + m_flRefireTime; 197 | 198 | local attackDir = m_pEntity.GetUpVector(); 199 | attackDir.Multiply( m_flProjectileSpeed ); 200 | 201 | local shootPos = m_vecPosition; 202 | CHomingProjectile( this, shootPos, attackDir ); 203 | Swarm.PlaySound( SwarmSound.BossWeapon, SND_FIRE2 ); 204 | } 205 | break; 206 | } 207 | // Identical to Type1 but with SND_FIRE3 fire sound and 10% slower projectiles 208 | case ArmAttack.Type3: 209 | { 210 | if ( m_flNextAttackTime <= curtime ) 211 | { 212 | m_flNextAttackTime = curtime + m_flRefireTime; 213 | 214 | local attackDir = m_pEntity.GetUpVector(); 215 | attackDir.Multiply( m_flProjectileSpeed * 0.9 ); 216 | 217 | local shootPos = m_vecPosition; 218 | CProjectile( this, shootPos, attackDir ); 219 | Swarm.PlaySound( SwarmSound.BossWeapon, SND_FIRE3 ); 220 | } 221 | break; 222 | } 223 | } 224 | 225 | DebugDrawBBox(); 226 | 227 | return 0.0; 228 | } 229 | 230 | function CBossArm::TakeProjectileDamage( projectile ) 231 | { 232 | m_nHealth -= projectile.m_nDamage; 233 | 234 | if ( m_nHealth < 0 ) 235 | m_nHealth = 0; 236 | 237 | m_hOwner.UpdateHealthStats(); 238 | 239 | m_pEntity.SetRenderColor( 255, 255, 255 ); 240 | m_pEntity.SetContextThink( "RestoreColour", SUB_RestoreColour, 0.2 ); 241 | 242 | if ( m_nHealth == 0 ) 243 | { 244 | Destroy(); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/init.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | { 6 | CONST.TICK_INTERVAL <- IntervalPerTick(); 7 | if ( SERVER_DLL ) 8 | CONST.MAX_PLAYERS <- MaxPlayers(); 9 | 10 | const MASK_ALL = -1; 11 | 12 | CONST.vec3_origin <- Vector(); 13 | CONST.vec3_invalid <- Vector( FLT_MAX, FLT_MAX, FLT_MAX ); 14 | 15 | if ( !("Init" in Vector) ) 16 | Vector.Init <- Vector.Set; 17 | 18 | if ( !("Copy" in Vector) ) 19 | Vector.Copy <- Vector.Set; 20 | 21 | if ( !("Negate" in Vector) ) 22 | Vector.Negate <- function() 23 | { 24 | x = -x; y = -y; z = -z; 25 | } 26 | 27 | if ( !("Replicate" in Vector) ) 28 | Vector.Replicate <- function( f ) 29 | { 30 | x = y = z = f; 31 | } 32 | 33 | if ( !("Zero" in Vector) ) 34 | Vector.Zero <- function() 35 | { 36 | x = y = z = 0.0; 37 | } 38 | 39 | const FLT_MAX_N = -3.402823466e+38; 40 | if ( !("IsValidVector" in Vector) ) 41 | Vector.IsValidVector <- function() 42 | { 43 | return ( x > FLT_MAX_N && x < FLT_MAX ) && 44 | ( y > FLT_MAX_N && y < FLT_MAX ) && 45 | ( z > FLT_MAX_N && z < FLT_MAX ); 46 | } 47 | } 48 | 49 | if ( CLIENT_DLL ) 50 | { 51 | local printc = printc, format = format; 52 | 53 | ::print = function(s) 54 | { 55 | return printc( 230, 218, 115, s ); 56 | } 57 | 58 | ::printf = function(...) 59 | { 60 | return printc( 230, 218, 115, format.acall(vargv.insert(0,null)) ); 61 | } 62 | } 63 | 64 | Assert <- assert; 65 | 66 | function DPrint( s ) 67 | { 68 | if ( Convars.GetInt("developer") >= 1 ) 69 | return print(s); 70 | } 71 | 72 | function DPrintf(...) 73 | { 74 | if ( Convars.GetInt("developer") >= 1 ) 75 | return print(format.acall(vargv.insert(0,null))); 76 | } 77 | 78 | function __typeofclass( o ) 79 | { 80 | local c = o; 81 | if ( typeof c == "instance" ) 82 | c = c.getclass(); 83 | 84 | foreach ( k, v in Swarm ) 85 | { 86 | if ( (typeof v == "class") && (v == c) ) 87 | { 88 | return k; 89 | } 90 | } 91 | 92 | return "unknown"; 93 | } 94 | 95 | function ECHO_FUNC( params = "" ) 96 | { 97 | local level = 0; 98 | if ( (0 in params) && params[0] >= '0' && params[0] <= '9' ) 99 | { 100 | if ( Convars.GetStr("developer")[0] < params[0] ) 101 | return; 102 | } 103 | 104 | local si = getstackinfos(2); 105 | local env = si.locals["this"]; 106 | local klass = "unknown"; 107 | 108 | switch ( typeof env ) 109 | { 110 | case "instance": 111 | klass = __typeofclass( env ); 112 | break; 113 | case "table": 114 | if ( env == Swarm ) 115 | { 116 | klass = "Swarm"; 117 | break; 118 | } 119 | } 120 | 121 | if ( params.find("c") != null ) 122 | { 123 | local si = getstackinfos(3); 124 | printf( "[%s()", si.func ); 125 | printc( 255, 255, 255, format("%d", si.line) ); 126 | printf( "] -> " ); 127 | } 128 | 129 | if ( params.find("f") != null ) 130 | { 131 | printf( "[%d] ", GetFrameCount() ); 132 | } 133 | 134 | if ( params.find("t") != null ) 135 | { 136 | printf( "[%.4f] ", Time() ); 137 | } 138 | 139 | print( klass ); 140 | 141 | if ( params.find("a") != null ) 142 | { 143 | local address = env.tostring().slice( env.tostring().find( "0x" ), env.tostring().len() - 1 ); 144 | printc( 255, 255, 255, format("[%s]", address) ); 145 | } 146 | 147 | if ( params.find("p") != null ) 148 | { 149 | // TODO: print parameters 150 | } 151 | 152 | printf( "::%s()\n", si.func ); 153 | 154 | if ( params.find("s") != null ) 155 | { 156 | PrintStack(); 157 | } 158 | } 159 | 160 | local Init = function(...) 161 | { 162 | IncludeScript( "boss_swarm/swarm.nut" ); 163 | 164 | if ( SERVER_DLL ) 165 | { 166 | if ( vargv[0] == Entities.GetLocalPlayer() ) 167 | { 168 | Swarm.ServerInit(); 169 | } 170 | 171 | Swarm.Init( vargv[0] ); 172 | } 173 | else // CLIENT_DLL 174 | { 175 | Swarm.Init(); 176 | } 177 | } 178 | 179 | ListenToGameEvent( "player_spawn", function( event ) 180 | { 181 | if ( SERVER_DLL ) 182 | { 183 | Init( GetPlayerByUserID( event.userid ) ); 184 | } 185 | else // CLIENT_DLL 186 | { 187 | Init(); 188 | Entities.First().SetContextThink( "Swarm", function(_) { StopListeningToAllGameEvents( "Swarm" ); }, 0.01 ); 189 | } 190 | }, "Swarm" ); 191 | 192 | 193 | if ( !("GetPlayerByUserID" in this) ) 194 | { 195 | function GetPlayerByUserID(i) 196 | { 197 | for ( local p; p = Entities.FindByClassname( p, "player" ); ) 198 | if ( p.GetUserID() == i ) 199 | return p; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/item_pickup.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | local Swarm = this; 6 | 7 | class CItemPickup extends CEntity 8 | { 9 | m_szPickupSound = ""; 10 | m_flRadius = 8.0; 11 | m_Item = null; 12 | } 13 | 14 | function CItemPickup::constructor( position, item, material ) 15 | { 16 | base.constructor(); 17 | 18 | position.z = 0.0; 19 | m_vecPosition.Copy( position ); 20 | m_vecHullMins.Init( -m_flRadius, -m_flRadius, 0 ); 21 | m_vecHullMaxs.Init( m_flRadius, m_flRadius, 4 ); 22 | 23 | m_pEntity = Swarm.SpriteCreate( material, 1.0, 24 | MOVETYPE_NONE, position, vec3_origin, 25 | m_vecHullMins, m_vecHullMaxs ); 26 | 27 | m_Item = item; 28 | 29 | return Spawn(); 30 | } 31 | 32 | function CItemPickup::OnTouch( player ) 33 | { 34 | //player.EquipItem( item ); 35 | m_Item.ActivateOn( player ); 36 | m_pEntity.EmitSound( m_szPickupSound ); 37 | return Destroy(); 38 | } 39 | 40 | function CItemPickup::Frame(_) 41 | { 42 | foreach ( player in Swarm.m_Players ) 43 | { 44 | if ( m_vecPosition.DistTo( player.m_vecPosition ) < (m_flRadius+player.m_vecHullMaxs.x) ) 45 | { 46 | OnTouch( player ); 47 | return -1; 48 | } 49 | } 50 | 51 | DebugDrawBBox(); 52 | return 0.0; 53 | } 54 | 55 | function CItemPickup::Destroy() 56 | { 57 | local x = Swarm.m_Pickups.find( this ); 58 | if ( x != null ) 59 | Swarm.m_Pickups.remove( x ); 60 | m_pEntity.SetContextThink( "", null, 0.0 ); 61 | return m_pEntity.Destroy(); 62 | } 63 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/items.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | local Swarm = this; 6 | local Time = Time, NetMsg = NetMsg, Fmt = format, RandomFloat = RandomFloat, RandomInt = RandomInt; 7 | 8 | if ( SERVER_DLL ){ 9 | 10 | class CItemSpeedBoost extends CItem 11 | { 12 | m_ID = SwarmEquipment.SpeedBoost; 13 | m_nRarity = 1; 14 | 15 | constructor( owner ) 16 | { 17 | m_hOwner = owner; 18 | } 19 | 20 | function Activate() 21 | { 22 | m_hOwner.m_MoveParams = Swarm.moveparam_t({ friction = 12.0, move = 12.0, maxspeed = 10.0 }); 23 | } 24 | 25 | function Deactivate() 26 | { 27 | m_hOwner.m_MoveParams = m_hOwner.m_BaseMoveParams; 28 | } 29 | } 30 | 31 | class CItemPenetration extends CItem 32 | { 33 | m_ID = SwarmEquipment.Penetration; 34 | 35 | m_pInstance = null; 36 | m_nAmount = 1; 37 | 38 | constructor( owner ) 39 | { 40 | m_hOwner = owner; 41 | 42 | local chance = RandomFloat( 0.0, 1.0 ); 43 | 44 | if ( chance < 0.01 ) 45 | { 46 | m_nAmount = 3; 47 | m_nRarity = 3; 48 | } 49 | else if ( chance < 0.1 ) 50 | { 51 | m_nAmount = 2; 52 | m_nRarity = 2; 53 | } 54 | } 55 | 56 | function Activate() 57 | { 58 | if ( m_hOwner.m_CurWeapon ) 59 | { 60 | m_pInstance = m_hOwner.m_CurWeapon.weakref(); 61 | m_hOwner.m_CurWeapon.m_nPenetration += m_nAmount; 62 | ++m_hOwner.m_CurWeapon.m_Modifiers; 63 | } 64 | } 65 | 66 | function Deactivate() 67 | { 68 | if ( m_pInstance ) 69 | { 70 | m_pInstance.m_nPenetration -= m_nAmount; 71 | --m_pInstance.m_Modifiers; 72 | } 73 | } 74 | 75 | function NET_WriteData() 76 | { 77 | NetMsg.WriteByte( m_nRarity ); 78 | NetMsg.WriteByte( m_nAmount ); 79 | } 80 | } 81 | 82 | class CItemShield extends CItem 83 | { 84 | m_ID = SwarmEquipment.Shield; 85 | m_nRarity = 2; 86 | m_hShield = null; 87 | 88 | constructor( owner ) 89 | { 90 | m_hOwner = owner; 91 | } 92 | 93 | function Activate() 94 | { 95 | m_hShield = Swarm.CShield( m_hOwner, 96 | m_hOwner.m_pEntity, 97 | m_hOwner.m_vecPosition + m_hOwner.m_vecForward * 32.0, 98 | m_hOwner.m_vecForward ); 99 | m_hOwner.m_Shields.append( m_hShield ); 100 | 101 | m_hShield.m_nMaxHealth = 6; 102 | m_hShield.m_nHealth = 6; 103 | } 104 | 105 | function Deactivate() 106 | { 107 | if ( m_hShield ) 108 | { 109 | if ( m_hShield.m_nHealth > 0 ) 110 | { 111 | m_hShield.Destroy(); 112 | } 113 | 114 | local i = m_hOwner.m_Shields.find( m_hShield ); 115 | if ( i != null ) 116 | m_hOwner.m_Shields.remove( i ); 117 | } 118 | } 119 | } 120 | 121 | class CItemExtraLife extends CItem 122 | { 123 | m_ID = SwarmEquipment.ExtraLife; 124 | 125 | constructor( owner ) 126 | { 127 | m_hOwner = owner; 128 | } 129 | 130 | function Activate() 131 | { 132 | m_hOwner.m_nMaxHealth += 3; 133 | m_hOwner.m_nHealth = m_hOwner.m_nMaxHealth; 134 | 135 | m_hOwner.UpdateClient(); 136 | 137 | m_hOwner.m_pBasePlayer.SetHealth( m_hOwner.m_nHealth ); 138 | } 139 | 140 | function Deactivate() 141 | { 142 | m_hOwner.m_nMaxHealth -= 3; 143 | m_hOwner.m_nHealth = m_hOwner.m_nMaxHealth; 144 | 145 | m_hOwner.UpdateClient(); 146 | m_hOwner.m_pBasePlayer.SetHealth( m_hOwner.m_nHealth ); 147 | } 148 | } 149 | 150 | class CItemDamageBoost extends CItem 151 | { 152 | m_ID = SwarmEquipment.DamageBoost; 153 | 154 | m_pInstance = null; 155 | m_nAmount = 1; 156 | 157 | constructor( owner ) 158 | { 159 | m_hOwner = owner; 160 | 161 | local chance = RandomFloat( 0.0, 1.0 ); 162 | 163 | if ( chance < 0.005 ) 164 | { 165 | m_nAmount = 4; 166 | m_nRarity = 3; 167 | } 168 | else if ( chance < 0.01 ) 169 | { 170 | m_nAmount = 3; 171 | m_nRarity = 2; 172 | } 173 | else if ( chance < 0.3 ) 174 | { 175 | m_nAmount = 2; 176 | m_nRarity = 1; 177 | } 178 | } 179 | 180 | function Activate() 181 | { 182 | if ( m_hOwner.m_CurWeapon ) 183 | { 184 | m_pInstance = m_hOwner.m_CurWeapon.weakref(); 185 | m_hOwner.m_CurWeapon.m_nDamage += m_nAmount; 186 | ++m_hOwner.m_CurWeapon.m_Modifiers; 187 | } 188 | } 189 | 190 | function Deactivate() 191 | { 192 | if ( m_pInstance ) 193 | { 194 | m_pInstance.m_nDamage -= m_nAmount; 195 | --m_pInstance.m_Modifiers; 196 | } 197 | } 198 | 199 | function NET_WriteData() 200 | { 201 | NetMsg.WriteByte( m_nRarity ); 202 | NetMsg.WriteByte( m_nAmount ); 203 | } 204 | } 205 | 206 | class CItemFastShoot extends CItem 207 | { 208 | m_ID = SwarmEquipment.FastShoot; 209 | 210 | m_pInstance = null; 211 | m_flMultiplier = 0.0; 212 | m_flAmount = 0.0; 213 | 214 | constructor( owner ) 215 | { 216 | m_hOwner = owner; 217 | m_flMultiplier = RandomFloat( 0.1, 0.75 ); 218 | 219 | if ( m_flMultiplier > 0.65 ) 220 | { 221 | m_nRarity = 2; 222 | } 223 | else if ( m_flMultiplier > 0.5 ) 224 | { 225 | m_nRarity = 1; 226 | } 227 | } 228 | 229 | function Activate() 230 | { 231 | if ( m_hOwner.m_CurWeapon ) 232 | { 233 | m_pInstance = m_hOwner.m_CurWeapon.weakref(); 234 | m_flAmount = m_hOwner.m_CurWeapon.m_flRefireTime * m_flMultiplier; 235 | m_hOwner.m_CurWeapon.m_flRefireTime -= m_flAmount; 236 | ++m_hOwner.m_CurWeapon.m_Modifiers; 237 | } 238 | } 239 | 240 | function Deactivate() 241 | { 242 | if ( m_pInstance ) 243 | { 244 | m_pInstance.m_flRefireTime += m_flAmount; 245 | --m_pInstance.m_Modifiers; 246 | } 247 | } 248 | 249 | function NET_WriteData() 250 | { 251 | NetMsg.WriteByte( m_nRarity ); 252 | NetMsg.WriteByte( m_flMultiplier * 100.0 ); 253 | } 254 | } 255 | 256 | class CItemNoReload extends CItem 257 | { 258 | m_ID = SwarmEquipment.NoReload; 259 | 260 | m_nRarity = 1; 261 | m_pInstance = null; 262 | 263 | constructor( owner ) 264 | { 265 | m_hOwner = owner; 266 | } 267 | 268 | function Activate() 269 | { 270 | if ( m_hOwner.m_CurWeapon ) 271 | { 272 | m_pInstance = m_hOwner.m_CurWeapon.weakref(); 273 | // HACKHACK: 274 | m_hOwner.m_CurWeapon.m_nClip = INT_MAX; 275 | ++m_hOwner.m_CurWeapon.m_Modifiers; 276 | } 277 | } 278 | 279 | function Deactivate() 280 | { 281 | if ( m_pInstance ) 282 | { 283 | m_pInstance.m_nClip = m_pInstance.getclass().m_nClip; 284 | --m_pInstance.m_Modifiers; 285 | } 286 | } 287 | } 288 | 289 | } // SERVER_DLL 290 | 291 | if ( CLIENT_DLL ){ 292 | 293 | class CItemSpeedBoost 294 | { 295 | m_ID = SwarmEquipment.SpeedBoost; 296 | 297 | function NET_ReadDataIntoItem( item ) 298 | { 299 | item.rarity = 1; 300 | item.tooltip = "movement speed boost"; 301 | } 302 | } 303 | 304 | class CItemPenetration 305 | { 306 | m_ID = SwarmEquipment.Penetration; 307 | 308 | function NET_ReadDataIntoItem( item ) 309 | { 310 | item.rarity = NetMsg.ReadByte(); 311 | item.tooltip = Fmt( "+%d bullet penetration", NetMsg.ReadByte() ); 312 | } 313 | } 314 | 315 | class CItemShield 316 | { 317 | m_ID = SwarmEquipment.Shield; 318 | 319 | function NET_ReadDataIntoItem( item ) 320 | { 321 | item.rarity = 2; 322 | item.tooltip = "+1 shield"; 323 | } 324 | } 325 | 326 | class CItemExtraLife 327 | { 328 | m_ID = SwarmEquipment.ExtraLife; 329 | 330 | function NET_ReadDataIntoItem( item ) 331 | { 332 | item.tooltip = "+3 health"; 333 | } 334 | } 335 | 336 | class CItemDamageBoost 337 | { 338 | m_ID = SwarmEquipment.DamageBoost; 339 | 340 | function NET_ReadDataIntoItem( item ) 341 | { 342 | item.rarity = NetMsg.ReadByte(); 343 | item.tooltip = Fmt( "+%d weapon damage", NetMsg.ReadByte() ); 344 | } 345 | } 346 | 347 | class CItemFastShoot 348 | { 349 | m_ID = SwarmEquipment.FastShoot; 350 | 351 | function NET_ReadDataIntoItem( item ) 352 | { 353 | item.rarity = NetMsg.ReadByte(); 354 | item.tooltip = Fmt( "+%d percent faster shooting", NetMsg.ReadByte() ); 355 | } 356 | } 357 | 358 | class CItemNoReload 359 | { 360 | m_ID = SwarmEquipment.NoReload; 361 | 362 | function NET_ReadDataIntoItem( item ) 363 | { 364 | item.tooltip = "no weapon reload"; 365 | } 366 | } 367 | 368 | } // CLIENT_DLL 369 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/map_background.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | local viewHeight = 512.0; 6 | local viewPos = Vector( 0, 160, viewHeight ); 7 | local playerPos = Vector( 0, viewPos.y-210, 0 ); 8 | local playerAng = Vector( 90, 0, 0 ); 9 | 10 | if ( SERVER_DLL ) 11 | { 12 | PrecacheModel( "swarm/player2.vmt" ); 13 | 14 | local pawn; 15 | 16 | local Init = function() 17 | { 18 | for ( local p; p = Entities.FindByName( p, ".shadow" ); ) 19 | { 20 | p.SetRenderMode( 2 ); 21 | p.SetRenderAlpha( 100 ); 22 | } 23 | 24 | local view = Entities.CreateByClassname( "point_viewcontrol" ); 25 | view.AddSpawnFlags( 8 | 128 ); 26 | view.SetFov( 70, 0 ); 27 | view.SetAbsAngles( Vector( 90, 90, 0 ) ); 28 | view.SetAbsOrigin( viewPos ); 29 | view.AcceptInput( "Enable", "", player, null ); 30 | 31 | local logo = Entities.FindByName( null, "logo" ); 32 | logo.SetSolid( 2 ); 33 | logo.RemoveSolidFlags( FSOLID_NOT_SOLID ); 34 | 35 | pawn = Entities.CreateByClassname( "env_sprite" ); 36 | pawn.SetModel( "swarm/player2.vmt" ); 37 | pawn.__KeyValueFromFloat( "scale", 0.15 ); 38 | DispatchSpawn( pawn ); 39 | pawn.SetLocalOrigin( playerPos ); 40 | pawn.SetLocalAngles( playerAng ); 41 | 42 | // block the view 43 | Entities.FindByName( null, ".aperture" ).SetLocalOrigin( viewPos - Vector( 0, 32, 8 ) ); 44 | } 45 | 46 | // player_spawn on client fires while worldent is null.. 47 | // Add artificial delay... 48 | ListenToGameEvent( "player_spawn", function( event ) 49 | { 50 | Init(); 51 | Entities.First().SetContextThink( "SwarmBG", function(_) 52 | { 53 | NetMsg.Start( "SwarmBG" ); 54 | NetMsg.WriteEntity( pawn ); 55 | NetMsg.Send( player, true ); 56 | 57 | Entities.First().SetContextThink( "SwarmBG1", function(_) 58 | { 59 | StopListeningToAllGameEvents("SwarmBG"); 60 | }, 0.0 ); 61 | }, 0.5 ); 62 | }, "SwarmBG" ); 63 | 64 | NetMsg.Receive( "Swarm.EE", function( basePlayer ) 65 | { 66 | local t = { rainbow = 1 } 67 | SaveTable( "Swarm.EE", t ); 68 | } ); 69 | 70 | NetMsg.Receive( "ClientCommand", function( basePlayer ) 71 | { 72 | SendToConsole( NetMsg.ReadString() ); 73 | } ); 74 | } 75 | 76 | if ( CLIENT_DLL ) 77 | { 78 | IncludeScript( "boss_swarm/vs_math" ); 79 | 80 | local m_flFadeStartTime = 0.0; 81 | local m_pAperture, m_pEntity; 82 | local m_flFadeFadeTime = 0.0; 83 | local m_bFadeIn = 0.0; 84 | local m_fnFadeCallback; 85 | local hover = false; 86 | local click = false; 87 | 88 | local function ApertureFadeThink(_) 89 | { 90 | local curtime = Time(); 91 | local t = ( curtime - m_flFadeStartTime ) / m_flFadeFadeTime; 92 | 93 | if ( m_bFadeIn ) 94 | { 95 | t = 1.0 - t; 96 | if ( t < 0.0 ) 97 | { 98 | if ( m_fnFadeCallback ) 99 | { 100 | m_fnFadeCallback(); 101 | m_fnFadeCallback = null; 102 | } 103 | return -1; 104 | } 105 | } 106 | else 107 | { 108 | if ( t >= 1.0 ) 109 | { 110 | m_pAperture.SetLocalOrigin( Vector(0,0,768) ); 111 | if ( m_fnFadeCallback ) 112 | { 113 | m_fnFadeCallback(); 114 | m_fnFadeCallback = null; 115 | } 116 | return -1; 117 | } 118 | } 119 | 120 | local viewOrigin = CurrentViewOrigin(); 121 | local pos = m_pEntity.GetLocalOrigin() 122 | .Subtract( viewOrigin ).Multiply( Bias( t, 0.2 ) ).Add( viewOrigin ); 123 | m_pAperture.SetLocalOrigin( pos ); 124 | return 0.0; 125 | } 126 | 127 | local function ApertureFade( dir, time, delay, callback ) 128 | { 129 | m_flFadeStartTime = Time() + delay; 130 | m_flFadeFadeTime = time; 131 | m_bFadeIn = dir; 132 | m_fnFadeCallback = callback; 133 | 134 | if ( RandomFloat( 0.0, 1.0 ) < 0.1 ) 135 | { 136 | m_pAperture = Entities.FindByName( null, ".aperture2" ); 137 | } 138 | else 139 | { 140 | m_pAperture = Entities.FindByName( null, ".aperture" ); 141 | } 142 | 143 | return Entities.First().SetContextThink( "Swarm.Fade", ApertureFadeThink, delay ); 144 | } 145 | 146 | local function DoClick() 147 | { 148 | NetMsg.Start( "Swarm.EE" ); 149 | NetMsg.Send(); 150 | 151 | SendToConsole( "fadeout 1.5" ); 152 | ApertureFade( false, 1.5, 0.0, function() 153 | { 154 | SendToConsole( "map boss_swarm_a" ); 155 | } ); 156 | } 157 | 158 | local function ClientThink(_) 159 | { 160 | local x = input.GetAnalogValue( AnalogCode.MOUSE_X ); 161 | local y = input.GetAnalogValue( AnalogCode.MOUSE_Y ); 162 | playerPos = m_pEntity.GetLocalOrigin(); 163 | 164 | local ray = ScreenToRay( x, y ); 165 | local t = VS.IntersectRayWithPlane( viewPos, ray, Vector(0,0,1), playerPos.z ); 166 | ray.Multiply( t ).Add( viewPos ); 167 | local dt = ray - playerPos; 168 | playerAng.y = VS.VecToYaw( dt ); 169 | m_pEntity.SetLocalAngles( playerAng ); 170 | 171 | if ( click ) 172 | { 173 | local t = clock() * 16.0; 174 | local r = sin( t ) * 127 + 128; 175 | local g = sin( t + PI * 0.5 ) * 127 + 128; 176 | local b = sin( t + PI ) * 127 + 128; 177 | m_pEntity.SetRenderColor( r, g, b ); 178 | return 0.0; 179 | } 180 | 181 | // GameTrace doesn't hit for whatever reason... 182 | local mouseover = VS.IsRayIntersectingSphere( viewPos, ray.Subtract( viewPos ), playerPos, 20.0, 0.0 ); 183 | local mouseclick = input.IsButtonDown( ButtonCode.MOUSE_LEFT ); 184 | 185 | if ( mouseover ) 186 | { 187 | if ( !click && hover && mouseclick ) 188 | { 189 | click = true; 190 | DoClick(); 191 | return 0.0; 192 | } 193 | else if ( !hover && !mouseclick ) 194 | { 195 | hover = true; 196 | local dir = playerPos - viewPos; 197 | dir.Norm(); 198 | dir.Multiply( -96.0 ); 199 | m_pEntity.SetLocalOrigin( playerPos + dir ); 200 | } 201 | else if ( hover ) 202 | { 203 | local t = clock() * 16.0; 204 | local r = sin( t ) * 127 + 128; 205 | local g = sin( t + PI * 0.5 ) * 127 + 128; 206 | local b = sin( t + PI ) * 127 + 128; 207 | m_pEntity.SetRenderColor( r, g, b ); 208 | } 209 | } 210 | else if ( hover ) 211 | { 212 | hover = false; 213 | local dir = playerPos - viewPos; 214 | dir.Norm(); 215 | dir.Multiply( 96.0 ); 216 | m_pEntity.SetLocalOrigin( playerPos + dir ); 217 | m_pEntity.SetRenderColor( 255, 255, 255 ); 218 | } 219 | 220 | return 0.0; 221 | } 222 | 223 | NetMsg.Receive( "SwarmBG", function() 224 | { 225 | m_pEntity = NetMsg.ReadEntity(); 226 | 227 | // Net message can be received before entities have spawned. 228 | // The artifical delay on server tries to hack this away. 229 | if ( !Entities.First() ) 230 | printf( "no world @%.4f [%d]\n", Time(), GetFrameCount() ); 231 | 232 | ApertureFade( true, 2.0, 0.0, null ); 233 | 234 | Entities.First().SetContextThink( "SwarmBG", ClientThink, 0.0 ); 235 | } ); 236 | 237 | function SendToConsole( str ) 238 | { 239 | NetMsg.Start( "ClientCommand" ); 240 | NetMsg.WriteString( str ); 241 | return NetMsg.Send(); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/object.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | 6 | local Swarm = this; 7 | local Vector = Vector, SpawnEntityFromTable = SpawnEntityFromTable, atan2 = atan2, 8 | TraceHullComplex = TraceHullComplex; 9 | 10 | local Convars = Convars; 11 | 12 | local SUB_SetVisible = function( ent ) 13 | { 14 | // Entity might have been killed before it had time to become visible 15 | if ( ent ) 16 | ent.SetRenderAlpha( 255 ); 17 | } 18 | 19 | local spritekv = 20 | { 21 | model = "swarm/projectile1.vmt", 22 | angles = Vector( 90, 0, 0 ), 23 | origin = Vector(), 24 | basevelocity = Vector(), 25 | scale = 1.0, 26 | framerate = 0.0, 27 | frame = 0.0 28 | } 29 | 30 | // NOTE: Using sprites are limiting for controlling draw order. 31 | function SpriteCreate( sprite, scale = 1.0, 32 | movetype = MOVETYPE_NOCLIP, origin = vec3_origin, velocity = vec3_origin, 33 | mins = null, maxs = null ) 34 | { 35 | spritekv.model = sprite; 36 | spritekv.origin.Copy( origin ); 37 | spritekv.basevelocity.Copy( velocity ); 38 | spritekv.scale = scale; 39 | 40 | local p = SpawnEntityFromTable( "env_sprite", spritekv ); 41 | 42 | // for debugging draw perf 43 | //local p; 44 | //{ 45 | // p = Entities.CreateByClassname( "info_null" ); 46 | // p.SetLocalOrigin( origin ); 47 | // p.SetVelocity( velocity ); 48 | // p.SetSolid( 0 ); 49 | //} 50 | 51 | p.AddSolidFlags( FSOLID_NOT_SOLID ); 52 | p.SetMoveType( movetype ); 53 | 54 | if ( movetype == MOVETYPE_STEP ) 55 | { 56 | p.AddFlag( FL_FLY ); 57 | } 58 | 59 | // HACKHACK: The entity is stationary for 2 frames. 60 | // Keep it invisible during that time to give a smooth look. 61 | if ( velocity != vec3_origin ) 62 | { 63 | p.SetRenderMode( 2 ); 64 | p.SetRenderAlpha( 0 ); 65 | p.SetContextThink( "vis", SUB_SetVisible, TICK_INTERVAL*3 ); 66 | } 67 | 68 | if ( mins ) 69 | p.SetSize( mins, maxs ); 70 | 71 | return p; 72 | } 73 | 74 | class CItem 75 | { 76 | m_nTeam = 0; 77 | m_ID = SwarmEquipment.None; 78 | m_iSlot = -1; 79 | m_hOwner = null; 80 | m_nRarity = 0; 81 | 82 | constructor( owner ) 83 | { 84 | m_hOwner = owner; 85 | } 86 | 87 | Activate = dummy; 88 | Deactivate = dummy; 89 | NET_WriteData = dummy; 90 | } 91 | 92 | class CEntity 93 | { 94 | m_nTeam = 0; 95 | m_pEntity = null; 96 | m_vecVelocity = null; 97 | m_vecPosition = null; 98 | m_vecAngles = null; 99 | m_vecForward = null; 100 | m_vecHullMins = null; 101 | m_vecHullMaxs = null; 102 | 103 | m_nHealth = 1; 104 | 105 | constructor() 106 | { 107 | m_vecVelocity = Vector(); 108 | m_vecPosition = Vector(); 109 | m_vecAngles = Vector( 90, 0, 0 ); 110 | m_vecForward = Vector( 1, 0, 0 ); 111 | m_vecHullMins = Vector(); 112 | m_vecHullMaxs = Vector(); 113 | } 114 | 115 | function Spawn() 116 | { 117 | ECHO_FUNC("3a"); 118 | 119 | return m_pEntity.SetContextThink( "", Frame.bindenv(this), 0.0 ); 120 | } 121 | 122 | // 123 | // Use m_pEntity.GetUpVector() instead of m_vecForward when parented! 124 | // 125 | // TODO: Maybe just use own transforms for convenience 126 | // 127 | function SetParent( pParent ) 128 | { 129 | m_pEntity.SetParent( pParent, "" ); 130 | m_vecAngles.x = 0.0; 131 | } 132 | 133 | function SetForward( forward ) 134 | { 135 | m_vecForward.Copy( forward ); 136 | m_vecAngles.y = atan2( forward.y, forward.x ) * RAD2DEG; 137 | return m_pEntity.SetLocalAngles( m_vecAngles ); 138 | } 139 | 140 | function SetAngle( yaw ) 141 | { 142 | m_vecAngles.y = yaw; 143 | VS.AngleVectors( m_vecAngles, m_vecForward ); 144 | return m_pEntity.SetLocalAngles( m_vecAngles ); 145 | } 146 | 147 | function RotateByAngle( dy ) 148 | { 149 | local forward = m_vecForward; 150 | VS.VectorYawRotate( forward, dy, forward ); 151 | m_vecAngles.y = atan2( forward.y, forward.x ) * RAD2DEG; 152 | return m_pEntity.SetLocalAngles( m_vecAngles ); 153 | } 154 | 155 | function RotateBaseEntityByAngle( ent, dy ) 156 | { 157 | local forward = ent.GetForwardVector(); 158 | VS.VectorYawRotate( forward, dy, forward ); 159 | return ent.SetLocalAngles( VS.VectorAngles( forward ) ); 160 | return ent.SetForwardVector( forward ); 161 | } 162 | 163 | function DebugDrawBBox() 164 | { 165 | if ( !Convars.GetInt("swarm_debugdraw") ) 166 | return; 167 | 168 | local forward, right; 169 | 170 | if ( m_pEntity.GetMoveParent() ) 171 | { 172 | forward = m_pEntity.GetUpVector(); 173 | right = m_pEntity.GetRightVector(); 174 | } 175 | else 176 | { 177 | forward = m_vecForward; 178 | right = forward.Cross( Vector(0,0,1) ); 179 | } 180 | 181 | local org = m_vecPosition; 182 | debugoverlay.Line( org, org + forward * 12, 255, 0, 0, true, -1 ); 183 | debugoverlay.Line( org, org + right * 12, 0, 255, 0, true, -1 ); 184 | //debugoverlay.Box( org, m_vecHullMins, m_vecHullMaxs, 255, 255, 255, 2, -1 ); 185 | return debugoverlay.Circle( org, Vector(0,1,0), Vector(1,0,0), m_vecHullMaxs.x, 255, 255, 255, 2, true, -1 ); 186 | } 187 | 188 | function Frame( m_pEntity ) 189 | { 190 | return 0.0; 191 | } 192 | 193 | Destroy = dummy; 194 | TakeProjectileDamage = dummy; 195 | } 196 | 197 | local s_nDepth = 0; 198 | 199 | function CEntity::ResolveCollisions() 200 | { 201 | if ( s_nDepth > 2 ) 202 | printf( "[%s] [%d] collision resolution depth %d\n", ""+this GetFrameCount(), s_nDepth ); 203 | 204 | if ( s_nDepth > 6 ) 205 | { 206 | printf( "Entity%s is stuck!\n", ""+this ); 207 | // TODO: unstuck 208 | return; 209 | } 210 | 211 | local vecNext = m_vecPosition + m_vecVelocity; 212 | 213 | local tr = TraceHullComplex( m_vecPosition, vecNext, m_vecHullMins, m_vecHullMaxs, m_pEntity, MASK_SOLID, COLLISION_GROUP_NONE ); 214 | 215 | if ( tr.DidHit() ) 216 | { 217 | local normal = tr.Plane().normal; 218 | 219 | m_vecPosition.Copy( tr.EndPos() ); 220 | m_vecVelocity.Subtract( normal.Multiply( m_vecVelocity.Dot( normal ) ) ); 221 | 222 | ++s_nDepth; 223 | tr.Destroy(); 224 | 225 | return ResolveCollisions(); 226 | } 227 | 228 | s_nDepth = 0; 229 | tr.Destroy(); 230 | 231 | m_vecPosition.Copy( vecNext ); 232 | return m_pEntity.SetLocalOrigin( vecNext ); 233 | } 234 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/projectile_simple.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( "CSimpleProjectile" in this ) 6 | return; 7 | 8 | local Swarm = this; 9 | local Vector = Vector, array = array, 10 | TraceLineComplex = TraceLineComplex, DispatchParticleEffect = DispatchParticleEffect; 11 | 12 | PrecacheModel( "swarm/projectile2.vmt" ); 13 | PrecacheParticleSystem( "impact_metal" ); 14 | 15 | class CSimpleProjectile extends CEntity 16 | { 17 | m_flLifeTime = 2.0; 18 | m_flRadius = 4.0; 19 | m_nDamage = 1; 20 | m_iMaxHits = 1; 21 | m_flInitVel = 0.0; 22 | m_iHits = 0; 23 | m_PreviousHits = null; 24 | } 25 | 26 | function CSimpleProjectile::constructor( ownerWeapon, position, velocity ) 27 | { 28 | Swarm.m_Projectiles.append( this ); 29 | 30 | m_vecPosition = Vector().Copy( position ); 31 | 32 | m_nTeam = ownerWeapon.m_nTeam; 33 | m_iMaxHits = ownerWeapon.m_nPenetration; 34 | m_nDamage = ownerWeapon.m_nDamage; 35 | 36 | m_PreviousHits = array( m_iMaxHits ); 37 | 38 | m_flInitVel = velocity.LengthSqr(); 39 | 40 | local ent = m_pEntity = Swarm.SpriteCreate( "swarm/projectile2.vmt", 0.15, 41 | MOVETYPE_FLY, position, velocity, 42 | Vector( -2, -2, 0 ), Vector( 2, 2, 2 ) ); 43 | 44 | ent.SetContextThink( "Expire", ExpireThink.bindenv(this), m_flLifeTime ); 45 | 46 | return Spawn(); 47 | } 48 | 49 | function CSimpleProjectile::ExpireThink( m_pEntity ) 50 | { 51 | // HACKHACK: just glueing everything together in the last day 52 | if ( !this ) 53 | return; 54 | 55 | DispatchParticleEffect( "impact_metal", m_vecPosition, vec3_origin ); 56 | Destroy(); 57 | } 58 | 59 | function CSimpleProjectile::Destroy() 60 | { 61 | Swarm.m_Projectiles.remove( Swarm.m_Projectiles.find( this ) ); 62 | 63 | m_pEntity.SetContextThink( "", null, 0.0 ); 64 | m_pEntity.SetContextThink( "Expire", null, 0.0 ); 65 | return m_pEntity.Destroy(); 66 | } 67 | 68 | // 69 | // TODO: Lose damage after penetration. 70 | // 71 | function CSimpleProjectile::Frame( m_pEntity ) 72 | { 73 | local pos = m_pEntity.GetLocalOrigin(); 74 | local radius = m_flRadius; 75 | //local damage = m_flDamage; 76 | local penetration = m_iMaxHits; 77 | local team = m_nTeam; 78 | 79 | //debugoverlay.Circle( pos, Vector(0,1,0), Vector(1,0,0), radius, 255, 255, 255, 0, true, -1 ); 80 | 81 | foreach ( obj in Swarm.m_HurtableEntities ) 82 | { 83 | if ( ( obj.m_nTeam != team ) && 84 | ( obj.m_vecPosition.DistTo( pos ) < (radius+obj.m_vecHullMaxs.x) ) && 85 | ( ( penetration == 1 ) || (m_PreviousHits.find(obj) == null) ) ) 86 | { 87 | // HACKHACK: Yes, this is horrible I know. But I'm out of time. 88 | if ( team == 1 ) 89 | { 90 | local player = Swarm.m_Players[0].m_pBasePlayer; 91 | SteamAchievements.IncrementStat( player, "ACH_MANY_DAMAGE", 1 ); 92 | local stat = SteamAchievements.GetStat( player, "ACH_MANY_DAMAGE" ); 93 | if ( (stat % 2000) == 0 ) 94 | { 95 | SteamAchievements.IndicateAchievementProgress( player, "ACH_MANY_DAMAGE" ); 96 | } 97 | } 98 | 99 | obj.TakeProjectileDamage( this ); 100 | 101 | m_PreviousHits[m_iHits] = obj; 102 | 103 | if ( ++m_iHits >= penetration ) 104 | { 105 | Destroy(); 106 | return -1; 107 | } 108 | } 109 | } 110 | 111 | local vel = m_pEntity.GetVelocity(); 112 | if ( vel.LengthSqr() < m_flInitVel ) 113 | { 114 | // Impact particle effect 115 | 116 | // Position delta will be 0 when projectiles are destroyed in the frame they are spawned, 117 | // causing incorrect particle positioning. 118 | // I _could_ fix this by keeping track of more elements, but it's not worth it. 119 | if ( pos.IsEqualTo( m_vecPosition ) ) 120 | { 121 | Destroy(); 122 | return -1; 123 | } 124 | 125 | // vecDelta 126 | pos.Subtract( m_vecPosition ); 127 | pos.Norm(); 128 | pos.Multiply( MAX_COORD_FLOAT ); 129 | 130 | local tr = TraceLineComplex( m_vecPosition, pos, m_pEntity, MASK_SOLID, COLLISION_GROUP_NONE ); 131 | local endpos = tr.EndPos(); 132 | local normal = tr.Plane().normal; 133 | 134 | DispatchParticleEffect( "impact_metal", endpos, VS.VectorAngles( normal ) ); 135 | 136 | tr.Destroy(); 137 | Destroy(); 138 | return -1; 139 | } 140 | 141 | m_vecPosition.Copy( pos ); 142 | 143 | return 0.0; 144 | } 145 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/shield.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( "CShield" in this ) 6 | return; 7 | 8 | local Swarm = this; 9 | local Time = Time; 10 | 11 | PrecacheModel( "swarm/shield3.vmt" ); 12 | 13 | local SUB_RestoreColour = function( ent ) 14 | { 15 | if ( ent ) 16 | ent.SetRenderColor( 0, 120, 255 ); 17 | } 18 | 19 | class CShield extends CEntity 20 | { 21 | m_hOwner = null; 22 | m_nMaxHealth = 30; 23 | m_nHealth = 30; 24 | } 25 | 26 | function CShield::constructor( owner, pParent, position, forward ) 27 | { 28 | base.constructor(); 29 | 30 | m_hOwner = owner; 31 | m_nTeam = owner.m_nTeam; 32 | 33 | Swarm.m_HurtableEntities.append( this ); 34 | 35 | position.z = 0.0; 36 | m_vecPosition.Copy( position ); 37 | m_vecHullMins.Init( -16, -16, 0 ); 38 | m_vecHullMaxs.Init( 16, 16, 4 ); 39 | 40 | m_pEntity = Swarm.SpriteCreate( "swarm/shield3.vmt", 0.5, 41 | MOVETYPE_NONE, position, vec3_origin, 42 | m_vecHullMins, m_vecHullMaxs ); 43 | 44 | m_pEntity.SetRenderColor( 0, 120, 255 ); 45 | 46 | SetForward( forward ); 47 | SetParent( pParent ); 48 | 49 | return Spawn(); 50 | } 51 | 52 | function CShield::Frame(_) 53 | { 54 | m_vecPosition.Copy( m_pEntity.GetOrigin() ); 55 | DebugDrawBBox(); 56 | return 0.0; 57 | } 58 | 59 | function CShield::Destroy() 60 | { 61 | local x = Swarm.m_HurtableEntities.find( this ); 62 | if ( x != null ) 63 | Swarm.m_HurtableEntities.remove( x ); 64 | m_pEntity.SetContextThink( "", null, 0.0 ); 65 | return m_pEntity.Destroy(); 66 | } 67 | 68 | function CShield::TakeProjectileDamage( projectile ) 69 | { 70 | m_nHealth -= projectile.m_nDamage; 71 | 72 | if ( m_nHealth < 0 ) 73 | m_nHealth = 0; 74 | 75 | m_hOwner.UpdateHealthStats(); 76 | 77 | m_pEntity.SetRenderColor( 255, 255, 255 ); 78 | m_pEntity.SetContextThink( "RestoreColour", SUB_RestoreColour, 0.2 ); 79 | 80 | if ( m_nHealth == 0 ) 81 | { 82 | Destroy(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/snd.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // A bit of a hacked solution that limits the amount of sounds played at once 6 | // and plays specific type of sounds at specific entities. 7 | // 8 | 9 | local Swarm = this; 10 | 11 | enum SwarmSound 12 | { 13 | PlayerWeapon, 14 | BossWeapon, 15 | } 16 | 17 | m_SoundQueue <- 18 | { 19 | [SwarmSound.PlayerWeapon] = {}, 20 | [SwarmSound.BossWeapon] = {}, 21 | } 22 | 23 | function PlaySound( chan, sound ) 24 | { 25 | local pChan = m_SoundQueue[ chan ]; 26 | 27 | if ( sound in pChan ) 28 | { 29 | local ref = pChan[ sound ]; 30 | if ( ref >= 2 ) 31 | return; 32 | 33 | ++pChan[ sound ]; 34 | return; 35 | } 36 | 37 | pChan[ sound ] <- 1; 38 | } 39 | 40 | function SoundFrame() 41 | { 42 | local queue = m_SoundQueue[SwarmSound.PlayerWeapon]; 43 | local target = Swarm.m_Players[0].m_pEntity; 44 | 45 | foreach ( sound, ref in queue ) 46 | { 47 | if ( ref ) 48 | { 49 | do { 50 | target.EmitSound( sound ); 51 | } while ( --ref ); 52 | queue[sound] = 0; 53 | } 54 | } 55 | 56 | queue = m_SoundQueue[SwarmSound.BossWeapon]; 57 | target = Swarm.m_hBigBoss; 58 | if ( target ) 59 | { 60 | target = target.m_pEntity; 61 | 62 | foreach ( sound, ref in queue ) 63 | { 64 | if ( ref ) 65 | { 66 | do { 67 | target.EmitSound( sound ); 68 | } while ( --ref ); 69 | queue[sound] = 0; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/weapon_basic.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( SERVER_DLL ){ 6 | 7 | IncludeScript( "boss_swarm/projectile_simple.nut", this ); 8 | 9 | local Swarm = this; 10 | local Time = Time, RandomFloat = RandomFloat; 11 | 12 | local SND_FIRE = "Weapon_AR2.NPC_Single"; 13 | local SND_EMPTY = "Weapon_AR2.Empty"; 14 | 15 | PrecacheSoundScript( SND_FIRE ); 16 | 17 | local CProjectile = class extends CSimpleProjectile 18 | { 19 | m_flLifeTime = 5.0; 20 | } 21 | 22 | class CWeapon_Basic extends CBaseWeapon 23 | { 24 | CProjectile = CProjectile; 25 | 26 | m_ID = SwarmEquipment.BasicGun; 27 | 28 | m_szSoundReload = "Weapon_357.RemoveLoader"; 29 | m_szSoundReloadEnd = "Weapon_Shotgun.Special1"; 30 | 31 | m_flProjectileSpeed = 250.0; 32 | m_flRefireTime = 0.175; 33 | m_flReloadTime = 1.0; 34 | m_nClip = 12; 35 | m_nAmmo = -1; 36 | m_nMaxClip = 12; 37 | 38 | constructor( owner ) 39 | { 40 | base.constructor( owner ); 41 | } 42 | } 43 | 44 | function CWeapon_Basic::Attack() 45 | { 46 | local curtime = Time(); 47 | if ( curtime < m_flNextAttackTime ) 48 | return; 49 | 50 | if ( m_nClip <= 0 ) 51 | { 52 | m_flNextAttackTime = curtime + m_flRefireTime * 0.5; 53 | return Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_EMPTY ); 54 | } 55 | 56 | m_flNextAttackTime = curtime + m_flRefireTime; 57 | 58 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 59 | 60 | local attackDir = m_hOwner.m_vecForward * 1; 61 | attackDir.x += RandomFloat( -0.25, 0.25 ); 62 | attackDir.y += RandomFloat( -0.25, 0.25 ); 63 | attackDir.Norm(); 64 | attackDir.Multiply( m_flProjectileSpeed ); 65 | 66 | local shootPos = ( m_hOwner.m_vecForward * 32.0 ).Add( m_hOwner.m_vecPosition ); 67 | CProjectile( this, shootPos, attackDir ); 68 | 69 | if ( --m_nClip == 0 ) 70 | { 71 | if ( m_nAmmo ) 72 | { 73 | return Reload(); 74 | } 75 | } 76 | } 77 | 78 | function CWeapon_Basic::NET_WriteData() 79 | { 80 | NetMsg.WriteByte( m_nDamage ); 81 | NetMsg.WriteByte( m_nPenetration ); 82 | NetMsg.WriteFloat( m_flProjectileSpeed ); 83 | NetMsg.WriteFloat( m_flRefireTime ); 84 | } 85 | 86 | } // SERVER_DLL 87 | 88 | if ( CLIENT_DLL ){ 89 | 90 | class CWeapon_Basic 91 | { 92 | function NET_ReadDataIntoItem( item ) 93 | { 94 | local damage = NetMsg.ReadByte(); 95 | local penetration = NetMsg.ReadByte(); 96 | local speed = NetMsg.ReadFloat(); 97 | local refire = NetMsg.ReadFloat(); 98 | item.tooltip = format( "Pistol\nDMG: %d\nPEN: %d\nSPD: %.4g\nTRG: %.4g\n", 99 | damage, penetration, speed, refire ); 100 | } 101 | } 102 | 103 | } // CLIENT_DLL 104 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/weapon_blast.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( SERVER_DLL ){ 6 | 7 | local Swarm = this; 8 | local Time = Time, RandomFloat = RandomFloat; 9 | 10 | local SND_FIRE = "Weapon_AR2.NPC_Double"; 11 | 12 | PrecacheSoundScript( SND_FIRE ); 13 | 14 | const BLAST_RANGE = 256.0; 15 | const RECHARGE_TIME = 10.0; 16 | 17 | class CWeapon_Blast extends CBaseWeapon 18 | { 19 | m_ID = SwarmEquipment.Blast; 20 | 21 | m_szSoundReloadEnd = "Weapon_AR2.Reload_Rotate"; 22 | 23 | m_flProjectileSpeed = 0.0; 24 | m_flRefireTime = 0.0; 25 | m_nClip = 1; 26 | m_nMaxClip = 1; 27 | m_flReloadTime = RECHARGE_TIME; 28 | m_flRange = BLAST_RANGE; 29 | 30 | constructor( owner ) 31 | { 32 | base.constructor( owner ); 33 | } 34 | } 35 | 36 | function CWeapon_Blast::Attack2() 37 | { 38 | local curtime = Time(); 39 | if ( curtime < m_flNextAttackTime ) 40 | return; 41 | 42 | m_flNextAttackTime = curtime + m_flRefireTime; 43 | 44 | // TODO: CSimpleProjectile::Destroy() doesn't have to remove itself from m_Projectiles immediately. 45 | local cache = []; 46 | local vecPosition = m_hOwner.m_vecPosition; 47 | local flRange = m_flRange; 48 | 49 | foreach ( projectile in Swarm.m_Projectiles ) 50 | { 51 | local vecTarget = projectile.m_vecPosition; 52 | 53 | if ( projectile.m_nTeam != m_nTeam && vecPosition.DistTo( vecTarget ) < (flRange+projectile.m_flRadius) ) 54 | { 55 | DispatchParticleEffect( "impact_metal", vecTarget, vec3_origin ); 56 | cache.append( projectile ); 57 | } 58 | } 59 | 60 | foreach ( projectile in cache ) 61 | { 62 | projectile.Destroy(); 63 | } 64 | 65 | // Yes, I'm using debugoverlay, what of it? 66 | debugoverlay.Circle( vecPosition, Vector(0,1,0), Vector(1,0,0), flRange, 10, 100, 255, 15, false, 0.1 ); 67 | 68 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 69 | 70 | if ( --m_nClip <= 0 ) 71 | { 72 | return Reload(); 73 | } 74 | } 75 | 76 | } // SERVER_DLL 77 | 78 | if ( CLIENT_DLL ){ 79 | 80 | class CWeapon_Blast 81 | { 82 | function NET_ReadDataIntoItem( item ) 83 | { 84 | item.tooltip = format( "Deletes nearby projectiles\n\nCooldown %.2gs", RECHARGE_TIME ); 85 | } 86 | } 87 | 88 | } // CLIENT_DLL 89 | 90 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/weapon_burstgun.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( SERVER_DLL ){ 6 | 7 | IncludeScript( "boss_swarm/projectile_simple.nut", this ); 8 | 9 | local Swarm = this; 10 | local Time = Time, RandomFloat = RandomFloat; 11 | 12 | local SND_FIRE = "Weapon_AR2.NPC_Single"; 13 | local SND_EMPTY = "Weapon_AR2.Empty"; 14 | 15 | PrecacheSoundScript( SND_FIRE ); 16 | 17 | local CProjectile = class extends CSimpleProjectile 18 | { 19 | m_flLifeTime = 2.0; 20 | } 21 | 22 | class CWeapon_BurstGun extends CBaseWeapon 23 | { 24 | CProjectile = CProjectile; 25 | 26 | m_ID = SwarmEquipment.BurstGun; 27 | 28 | m_szSoundReload = "Weapon_AR2.NPC_Reload"; 29 | m_szSoundReloadEnd = "Weapon_Shotgun.Special1"; 30 | 31 | m_nDamage = CSimpleProjectile.m_nDamage + 1; 32 | m_flProjectileSpeed = 420.0; 33 | m_flRefireTime = 0.5; 34 | m_flBurstRefireTime = 0.05; 35 | m_flReloadTime = 1.75; 36 | m_nMaxBurstShots = 3; 37 | 38 | m_nClip = 21; 39 | m_nAmmo = -1; 40 | m_nMaxClip = 21; 41 | 42 | m_flNextBurstTime = 0.0; 43 | m_nBurstShots = 0; 44 | 45 | constructor( owner ) 46 | { 47 | base.constructor( owner ); 48 | } 49 | 50 | function Activate() 51 | { 52 | return m_hOwner.m_pBasePlayer.SetContextThink( "WeaponFrame", Frame.bindenv(this), 0.0 ); 53 | } 54 | 55 | function Deactivate() 56 | { 57 | return m_hOwner.m_pBasePlayer.SetContextThink( "WeaponFrame", null, 0.0 ); 58 | } 59 | } 60 | 61 | function CWeapon_BurstGun::Frame( _ ) 62 | { 63 | if ( !this ) // HACKHACK: lol. weapon was freed but player is still thinking of it. 64 | return -1; 65 | 66 | if ( m_nBurstShots ) 67 | { 68 | local curtime = Time(); 69 | if ( curtime < m_flNextBurstTime ) 70 | return 0.0; 71 | 72 | if ( ++m_nBurstShots == m_nMaxBurstShots ) 73 | { 74 | m_flNextBurstTime = 0.0; 75 | m_nBurstShots = 0; 76 | m_flNextAttackTime = curtime + m_flRefireTime; 77 | } 78 | else 79 | { 80 | m_flNextBurstTime = curtime + m_flBurstRefireTime; 81 | } 82 | 83 | local shootPos = ( m_hOwner.m_vecForward * 32.0 ).Add( m_hOwner.m_vecPosition ); 84 | local attackDir = m_hOwner.m_vecForward * m_flProjectileSpeed; 85 | attackDir.x += RandomFloat( -15.0, 15.0 ); 86 | attackDir.y += RandomFloat( -15.0, 15.0 ); 87 | CProjectile( this, shootPos, attackDir ); 88 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 89 | 90 | if ( --m_nClip == 0 ) 91 | { 92 | if ( m_nAmmo ) 93 | { 94 | Reload(); 95 | } 96 | } 97 | } 98 | 99 | return 0.0; 100 | } 101 | 102 | function CWeapon_BurstGun::Attack() 103 | { 104 | if ( m_nBurstShots ) 105 | return; 106 | 107 | local curtime = Time(); 108 | if ( curtime < m_flNextAttackTime ) 109 | return; 110 | 111 | if ( m_nClip <= 0 ) 112 | { 113 | m_flNextAttackTime = curtime + m_flRefireTime * 0.5; 114 | return Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_EMPTY ); 115 | } 116 | 117 | local shootPos = ( m_hOwner.m_vecForward * 32.0 ).Add( m_hOwner.m_vecPosition ); 118 | local attackDir = m_hOwner.m_vecForward * 1; 119 | attackDir.x += RandomFloat( -0.1, 0.1 ); 120 | attackDir.y += RandomFloat( -0.1, 0.1 ); 121 | attackDir.Norm(); 122 | attackDir.Multiply( m_flProjectileSpeed ); 123 | 124 | CProjectile( this, shootPos, attackDir ); 125 | 126 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 127 | 128 | if ( --m_nClip == 0 ) 129 | { 130 | if ( m_nAmmo ) 131 | { 132 | return Reload(); 133 | } 134 | } 135 | else 136 | { 137 | m_flNextBurstTime = curtime + m_flBurstRefireTime; 138 | ++m_nBurstShots; 139 | } 140 | } 141 | 142 | function CWeapon_BurstGun::NET_WriteData() 143 | { 144 | NetMsg.WriteByte( m_nDamage ); 145 | NetMsg.WriteByte( m_nPenetration ); 146 | NetMsg.WriteFloat( m_flProjectileSpeed ); 147 | NetMsg.WriteFloat( m_flBurstRefireTime ); 148 | } 149 | 150 | } // SERVER_DLL 151 | 152 | if ( CLIENT_DLL ){ 153 | 154 | class CWeapon_BurstGun 155 | { 156 | function NET_ReadDataIntoItem( item ) 157 | { 158 | local damage = NetMsg.ReadByte(); 159 | local penetration = NetMsg.ReadByte(); 160 | local speed = NetMsg.ReadFloat(); 161 | local refire = NetMsg.ReadFloat(); 162 | item.tooltip = format( "Burstgun\nDMG: %d\nPEN: %d\nSPD: %.4g\nTRG: %.4g\n", 163 | damage, penetration, speed, refire ); 164 | } 165 | } 166 | 167 | } // CLIENT_DLL 168 | -------------------------------------------------------------------------------- /mapbase/boss_swarm/weapon_shotgun.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | 5 | if ( SERVER_DLL ){ 6 | 7 | IncludeScript( "boss_swarm/projectile_simple.nut", this ); 8 | 9 | local Swarm = this; 10 | local Time = Time, RandomFloat = RandomFloat; 11 | 12 | local SND_FIRE = "Weapon_AR2.NPC_Single"; 13 | 14 | PrecacheSoundScript( SND_FIRE ); 15 | 16 | local CProjectile = class extends CSimpleProjectile 17 | { 18 | m_flLifeTime = 2.0; 19 | } 20 | 21 | class CWeapon_Shotgun extends CBaseWeapon 22 | { 23 | CProjectile = CProjectile; 24 | 25 | m_ID = SwarmEquipment.Shotgun; 26 | 27 | m_szSoundReload = "Weapon_357.RemoveLoader"; 28 | m_szSoundReloadEnd = "Weapon_Shotgun.Special1"; 29 | 30 | m_flProjectileSpeed = 200.0; 31 | m_flRefireTime = 0.75; 32 | m_nClip = 6; 33 | m_nMaxClip = 6; 34 | m_flReloadTime = 2.25; 35 | 36 | constructor( owner ) 37 | { 38 | base.constructor( owner ); 39 | } 40 | } 41 | 42 | function CWeapon_Shotgun::Attack() 43 | { 44 | local curtime = Time(); 45 | if ( curtime < m_flNextAttackTime ) 46 | return; 47 | 48 | m_flNextAttackTime = curtime + m_flRefireTime; 49 | 50 | local shootPos = ( m_hOwner.m_vecForward * 32.0 ).Add( m_hOwner.m_vecPosition ); 51 | 52 | local v = Vector( RandomFloat( -12.0, 12.0 ), RandomFloat( -12.0, 12.0 ) ); 53 | shootPos.Copy( v.Add( shootPos ) ); 54 | shootPos.z = 0.0; 55 | 56 | local attackDir = VS.VectorYawRotate( m_hOwner.m_vecForward, RandomFloat( -10.0, 10.0 ) ) * 1; 57 | CProjectile( this, shootPos, attackDir.Multiply( m_flProjectileSpeed ) ); 58 | 59 | v = Vector( RandomFloat( -12.0, 12.0 ), RandomFloat( -12.0, 12.0 ) ); 60 | shootPos.Copy( v.Add( shootPos ) ); 61 | shootPos.z = 0.0; 62 | attackDir = VS.VectorYawRotate( m_hOwner.m_vecForward, RandomFloat( -10.0, 10.0 ) ) * 1; 63 | CProjectile( this, shootPos, attackDir.Multiply( m_flProjectileSpeed ) ); 64 | 65 | v = Vector( RandomFloat( -12.0, 12.0 ), RandomFloat( -12.0, 12.0 ) ); 66 | shootPos.Copy( v.Add( shootPos ) ); 67 | shootPos.z = 0.0; 68 | attackDir = VS.VectorYawRotate( m_hOwner.m_vecForward, RandomFloat( -10.0, 10.0 ) ) * 1; 69 | CProjectile( this, shootPos, attackDir.Multiply( m_flProjectileSpeed ) ); 70 | 71 | v = Vector( RandomFloat( -12.0, 12.0 ), RandomFloat( -12.0, 12.0 ) ); 72 | shootPos.Copy( v.Add( shootPos ) ); 73 | shootPos.z = 0.0; 74 | attackDir = VS.VectorYawRotate( m_hOwner.m_vecForward, RandomFloat( -10.0, 10.0 ) ) * 1; 75 | CProjectile( this, shootPos, attackDir.Multiply( m_flProjectileSpeed ) ); 76 | 77 | v = Vector( RandomFloat( -12.0, 12.0 ), RandomFloat( -12.0, 12.0 ) ); 78 | shootPos.Copy( v.Add( shootPos ) ); 79 | shootPos.z = 0.0; 80 | attackDir = VS.VectorYawRotate( m_hOwner.m_vecForward, RandomFloat( -10.0, 10.0 ) ) * 1; 81 | CProjectile( this, shootPos, attackDir.Multiply( m_flProjectileSpeed ) ); 82 | 83 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 84 | Swarm.PlaySound( SwarmSound.PlayerWeapon, SND_FIRE ); 85 | 86 | if ( --m_nClip == 0 ) 87 | { 88 | if ( m_nAmmo ) 89 | { 90 | return Reload(); 91 | } 92 | } 93 | } 94 | 95 | function CWeapon_Shotgun::NET_WriteData() 96 | { 97 | NetMsg.WriteByte( m_nDamage ); 98 | NetMsg.WriteByte( m_nPenetration ); 99 | NetMsg.WriteFloat( m_flProjectileSpeed ); 100 | NetMsg.WriteFloat( m_flRefireTime ); 101 | } 102 | 103 | } // SERVER_DLL 104 | 105 | if ( CLIENT_DLL ){ 106 | 107 | class CWeapon_Shotgun 108 | { 109 | function NET_ReadDataIntoItem( item ) 110 | { 111 | local damage = NetMsg.ReadByte(); 112 | local penetration = NetMsg.ReadByte(); 113 | local speed = NetMsg.ReadFloat(); 114 | local refire = NetMsg.ReadFloat(); 115 | item.tooltip = format( "Shotgun\nDMG: %d\nPEN: %d\nSPD: %.4g\nTRG: %.4g\n", 116 | damage, penetration, speed, refire ); 117 | } 118 | } 119 | 120 | } // CLIENT_DLL 121 | -------------------------------------------------------------------------------- /mapbase/cs_hud/fonts.nut: -------------------------------------------------------------------------------- 1 | 2 | surface.AddCustomFontFile( "resources/stratum2bold.ttf" ); 3 | 4 | local stratum = IsLinux() ? "Stratum2" : "Stratum2 Bold"; 5 | 6 | surface.CreateFont( "hud-HA-text", 7 | { 8 | "name" : stratum 9 | "tall" : 20 10 | "weight" : 500 11 | "antialias" : true 12 | "proportional" : true 13 | } ); 14 | 15 | surface.CreateFont( "hud-HA-text-blur", 16 | { 17 | "name" : stratum 18 | "blur" : 3 19 | "tall" : 20 20 | "weight" : 500 21 | "antialias" : true 22 | "proportional" : true 23 | } ); 24 | 25 | surface.CreateFont( "hud-HA-text-medium", 26 | { 27 | "name" : stratum 28 | "tall" : 16 29 | "weight" : 500 30 | "antialias" : true 31 | "proportional" : true 32 | } ); 33 | 34 | surface.CreateFont( "hud-HA-text-medium-blur", 35 | { 36 | "name" : stratum 37 | "blur" : 2 38 | "tall" : 16 39 | "weight" : 500 40 | "antialias" : true 41 | "proportional" : true 42 | } ); 43 | 44 | surface.CreateFont( "hud-HA-text-sm", 45 | { 46 | "name" : stratum 47 | "tall" : 10 48 | "weight" : 500 49 | "antialias" : true 50 | "proportional" : true 51 | } ); 52 | 53 | surface.CreateFont( "hud-HA-text-sm-blur", 54 | { 55 | "name" : stratum 56 | "blur" : 2 57 | "tall" : 10 58 | "weight" : 500 59 | "antialias" : true 60 | "proportional" : true 61 | } ); 62 | 63 | surface.CreateFont( "hud-HA-icon", 64 | { 65 | "name" : "HalfLife2" 66 | "tall" : 18 67 | "weight" : 0 68 | "antialias" : true 69 | "proportional" : true 70 | } ); 71 | 72 | surface.CreateFont( "hud-HA-icon-blur", 73 | { 74 | "name" : "HalfLife2" 75 | "blur" : 2 76 | "tall" : 18 77 | "weight" : 0 78 | "dropshadow" : true 79 | "proportional" : true 80 | } ); 81 | 82 | surface.CreateFont( "weapon-selection-item-name-text", 83 | { 84 | "name" : stratum 85 | "tall" : 6 86 | "weight" : 500 87 | "additive" : false 88 | "antialias" : true 89 | "dropshadow" : false 90 | "proportional" : true 91 | } ); 92 | 93 | surface.CreateFont( "weapon-selection-item-icon", 94 | { 95 | "name" : "HalfLife2" 96 | "tall" : 36 97 | "weight" : 0 98 | "antialias" : true 99 | "additive" : false 100 | "custom" : true 101 | "dropshadow" : true 102 | "proportional" : true 103 | } ); 104 | 105 | surface.CreateFont( "weapon-selection-item-icon-blur", 106 | { 107 | "name" : "HalfLife2" 108 | "blur" : 2 109 | "tall" : 36 110 | "weight" : 0 111 | "antialias" : true 112 | "additive" : false 113 | "custom" : true 114 | "dropshadow" : true 115 | "proportional" : true 116 | } ); 117 | 118 | surface.CreateFont( "hud-hint__text", 119 | { 120 | "name" : stratum // monospace doesn't work 121 | "tall" : 9 122 | "weight" : 500 123 | "antialias" : true 124 | "proportional" : true 125 | } ); 126 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudammo.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface, Fmt = format, NetProps = NetProps; 8 | 9 | 10 | class CSGOHudWeaponAmmo 11 | { 12 | constructor( player ) 13 | { 14 | this.player = player; 15 | } 16 | 17 | self = null 18 | player = null 19 | 20 | m_szAmmoClip = "" 21 | m_szAmmoReserve = "" 22 | m_szAmmoSecondary = "" 23 | 24 | m_bVisible = false 25 | m_bVisibleReserve = false 26 | m_bVisibleClip = false 27 | 28 | m_hWeapon = null 29 | m_nAmmo1 = -1 30 | m_nAmmo2 = -1 31 | m_nAmmoSecondary = -1 32 | 33 | m_hFont = null 34 | m_hFontBlur = null 35 | m_hFontSmall = null 36 | m_hFontSmallBlur = null 37 | m_hFontIcon = null 38 | m_hFontIconBlur = null 39 | 40 | m_TextureDataAmmo = null 41 | m_TextureDataAmmo2 = null 42 | m_chCurTextureDataAmmo = '\0' 43 | m_chCurTextureDataAmmo2 = '\0' 44 | 45 | m_nOffsetSecondaryIcon = 0 46 | m_nOffsetClipIcon = 0 47 | m_nOffsetClipLabel = 0 48 | m_nClipLabelWide = 0 49 | 50 | OnTick = null 51 | } 52 | 53 | function CSGOHudWeaponAmmo::AddTickSignal( t ) 54 | { 55 | self.SetCallback( "OnTick", OnTick.bindenv(this) ); 56 | return self.AddTickSignal( t ); 57 | } 58 | 59 | function CSGOHudWeaponAmmo::Init() 60 | { 61 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudWeaponAmmo" ); 62 | self.SetSize( XRES(640), YRES(480) ); 63 | self.SetVisible( false ); 64 | self.SetPaintBackgroundEnabled( false ); 65 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 66 | self.SetCallback( "Paint", Paint.bindenv(this) ); 67 | OnTick = OnTickWeapon; 68 | 69 | m_hFont = surface.GetFont( "hud-HA-text", true ); 70 | m_hFontBlur = surface.GetFont( "hud-HA-text-blur", true ); 71 | 72 | m_hFontSmall = surface.GetFont( "hud-HA-text-sm", true ); 73 | m_hFontSmallBlur = surface.GetFont( "hud-HA-text-sm-blur", true ); 74 | 75 | m_hFontIcon = surface.GetFont( "hud-HA-icon", true ); 76 | m_hFontIconBlur = surface.GetFont( "hud-HA-icon-blur", true ); 77 | 78 | m_TextureDataAmmo = 79 | { 80 | ["weapon_crowbar"] = 'c', 81 | ["weapon_stunstick"] = 'n', 82 | ["weapon_pistol"] = 'r', 83 | ["weapon_357"] = 'q', 84 | ["weapon_smg1"] = 'r', 85 | ["weapon_ar2"] = 'u', 86 | ["weapon_shotgun"] = 's', 87 | ["weapon_crossbow"] = 'w', 88 | ["weapon_frag"] = 'v', 89 | ["weapon_rpg"] = 'x', 90 | } 91 | 92 | m_TextureDataAmmo2 = 93 | { 94 | ["weapon_smg1"] = 't', 95 | ["weapon_ar2"] = 'z', 96 | ["weapon_slam"] = 'o', 97 | } 98 | } 99 | 100 | function CSGOHudWeaponAmmo::PerformLayout() 101 | { 102 | m_nOffsetSecondaryIcon = surface.GetCharacterWidth( m_hFont, 'W' ); 103 | m_nOffsetClipIcon = surface.GetCharacterWidth( m_hFontSmall, 'W' ) * 3 + YRES(32); 104 | m_nClipLabelWide = surface.GetCharacterWidth( m_hFont, '0' ) * 3 - YRES(4); 105 | 106 | // Recalculate 107 | m_bVisible = false; 108 | self.SetVisible( false ); 109 | m_hWeapon = null; 110 | OnTick(); 111 | } 112 | 113 | function CSGOHudWeaponAmmo::SetVehicle( type ) 114 | { 115 | switch ( type ) 116 | { 117 | case "APC": 118 | { 119 | m_bVisibleClip = true; 120 | m_bVisibleReserve = false; 121 | 122 | m_chCurTextureDataAmmo2 = m_TextureDataAmmo[ "weapon_rpg" ]; 123 | m_chCurTextureDataAmmo = m_TextureDataAmmo[ "weapon_ar2" ]; 124 | 125 | OnTick = OnTickAPC; 126 | break; 127 | } 128 | case "AIRBOAT": 129 | { 130 | m_bVisibleClip = true; 131 | m_bVisibleReserve = false; 132 | 133 | m_szAmmoSecondary = ""; 134 | m_chCurTextureDataAmmo = m_TextureDataAmmo[ "weapon_ar2" ]; 135 | 136 | OnTick = OnTickAirboat; 137 | break; 138 | } 139 | case null: 140 | { 141 | // Recalculate visibility state 142 | m_bVisible = false; 143 | self.SetVisible( false ); 144 | m_hWeapon = null; 145 | OnTickWeapon(); 146 | 147 | OnTick = OnTickWeapon; 148 | break; 149 | } 150 | } 151 | 152 | return self.SetCallback( "OnTick", OnTick.bindenv(this) ); 153 | } 154 | 155 | function CSGOHudWeaponAmmo::OnTickWeapon() 156 | { 157 | local weapon = player.GetActiveWeapon(); 158 | 159 | if ( !weapon ) 160 | { 161 | if ( m_hWeapon ) 162 | { 163 | m_bVisible = false; 164 | self.SetVisible( false ); 165 | 166 | m_bVisibleClip = false; 167 | m_bVisibleReserve = false; 168 | 169 | m_nAmmo1 = m_nAmmo2 = -1; 170 | m_hWeapon = null; 171 | } 172 | 173 | return; 174 | } 175 | 176 | local nAmmo1 = weapon.Clip1(); 177 | local nAmmo2 = 0; 178 | if ( nAmmo1 == -1 ) 179 | { 180 | nAmmo1 = player.GetAmmoCount( weapon.GetPrimaryAmmoType() ); 181 | } 182 | else 183 | { 184 | nAmmo2 = player.GetAmmoCount( weapon.GetPrimaryAmmoType() ); 185 | } 186 | 187 | local nAmmoSecondary = -1; 188 | if ( weapon.UsesSecondaryAmmo() ) 189 | { 190 | nAmmoSecondary = player.GetAmmoCount( weapon.GetSecondaryAmmoType() ); 191 | } 192 | 193 | // update on change 194 | if ( m_hWeapon != weapon || nAmmo1 != m_nAmmo1 || nAmmo2 != m_nAmmo2 || nAmmoSecondary != m_nAmmoSecondary ) 195 | { 196 | local szClassname = weapon.GetClassname(); 197 | 198 | m_hWeapon = weapon; 199 | m_nAmmo1 = nAmmo1; 200 | m_nAmmo2 = nAmmo2; 201 | m_nAmmoSecondary = nAmmoSecondary; 202 | 203 | if ( nAmmoSecondary != -1 ) 204 | { 205 | m_szAmmoSecondary = "" + nAmmoSecondary; 206 | m_chCurTextureDataAmmo2 = m_TextureDataAmmo2[ szClassname ]; 207 | } 208 | else 209 | { 210 | m_szAmmoSecondary = ""; 211 | } 212 | 213 | if ( weapon.UsesPrimaryAmmo() ) 214 | { 215 | m_chCurTextureDataAmmo = m_TextureDataAmmo[ szClassname ]; 216 | 217 | if ( weapon.UsesClipsForAmmo1() ) 218 | { 219 | SetAmmoInClip( nAmmo1 ); 220 | SetAmmoInReserve( nAmmo2 ); 221 | 222 | if ( !m_bVisibleClip ) 223 | m_bVisibleClip = true; 224 | 225 | if ( !m_bVisibleReserve ) 226 | m_bVisibleReserve = true; 227 | } 228 | else 229 | { 230 | SetAmmoInClip( nAmmo1 ); 231 | 232 | if ( !m_bVisibleClip ) 233 | m_bVisibleClip = true; 234 | 235 | if ( m_bVisibleReserve ) 236 | m_bVisibleReserve = false; 237 | } 238 | 239 | if ( !m_bVisible ) 240 | { 241 | m_bVisible = true; 242 | self.SetVisible( true ); 243 | } 244 | } 245 | // Only uses secondary ammo, set primary ammo invisible, draw secondary ammo if it's not invalid. 246 | // weapon_slam does this... 247 | else if ( nAmmoSecondary != -1 ) 248 | { 249 | m_chCurTextureDataAmmo = m_TextureDataAmmo2[ szClassname ]; 250 | 251 | if ( m_bVisibleClip ) 252 | m_bVisibleClip = false; 253 | 254 | if ( m_bVisibleReserve ) 255 | m_bVisibleReserve = false; 256 | 257 | if ( !m_bVisible ) 258 | { 259 | m_bVisible = true; 260 | self.SetVisible( true ); 261 | } 262 | } 263 | else 264 | { 265 | if ( m_bVisible ) 266 | { 267 | m_bVisible = false; 268 | self.SetVisible( false ); 269 | 270 | m_bVisibleClip = false; 271 | m_bVisibleReserve = false; 272 | } 273 | } 274 | } 275 | } 276 | 277 | function CSGOHudWeaponAmmo::OnTickAPC() 278 | { 279 | local nAmmo1 = NetProps.GetPropInt( CSHud.m_hVehicle, "m_iMachineGunBurstLeft" ); 280 | local nAmmoSecondary = NetProps.GetPropInt( CSHud.m_hVehicle, "m_iRocketSalvoLeft" ); 281 | 282 | // update on change 283 | if ( nAmmo1 != m_nAmmo1 || nAmmoSecondary != m_nAmmoSecondary ) 284 | { 285 | m_nAmmo1 = nAmmo1; 286 | m_nAmmoSecondary = nAmmoSecondary; 287 | m_szAmmoSecondary = "" + nAmmoSecondary; 288 | 289 | SetAmmoInClip( nAmmo1 ); 290 | 291 | if ( !m_bVisible ) 292 | { 293 | m_bVisible = true; 294 | self.SetVisible( true ); 295 | } 296 | } 297 | } 298 | 299 | function CSGOHudWeaponAmmo::OnTickAirboat() 300 | { 301 | local nAmmo1 = NetProps.GetPropInt( CSHud.m_hVehicle, "m_nAmmoCount" ); 302 | 303 | // update on change 304 | if ( nAmmo1 != m_nAmmo1 ) 305 | { 306 | m_nAmmo1 = nAmmo1; 307 | SetAmmoInClip( nAmmo1 ); 308 | 309 | if ( !m_bVisible ) 310 | { 311 | m_bVisible = true; 312 | self.SetVisible( true ); 313 | } 314 | } 315 | } 316 | 317 | // NOTE: CSGO ammo panel height does not match health panel height 318 | function CSGOHudWeaponAmmo::Paint() 319 | { 320 | local width = YRES(143); 321 | local height = YRES(22); 322 | 323 | local x0 = XRES(640) - width; 324 | local y0 = YRES(480) - height; 325 | 326 | // bg 327 | { 328 | local flAlpha = CSHud.m_flBackgroundAlpha; 329 | 330 | local w = YRES(44); 331 | local x = x0; 332 | surface.SetColor( 0x00, 0x00, 0x00, 0xcc * flAlpha ); 333 | surface.DrawFilledRectFade( x, y0, w, height, 0x00, 0xff, true ); 334 | x += w; 335 | w = YRES(85); 336 | surface.DrawFilledRect( x, y0, w, height ); 337 | surface.DrawFilledRectFade( x + w, y0, YRES(14), height, 0xff, 0x00, true ); 338 | } 339 | 340 | if ( m_bVisibleClip ) 341 | { 342 | local x = x0 + YRES(59.5); 343 | 344 | // icon blur 345 | surface.SetTextFont( m_hFontIconBlur ); 346 | surface.SetTextColor( 0x00, 0x00, 0x00, 0xff ); 347 | surface.SetTextPos( x + m_nOffsetClipIcon, y0 + YRES(4) ); 348 | surface.DrawUnicodeChar( m_chCurTextureDataAmmo, 0 ); 349 | 350 | // icon 351 | surface.SetTextFont( m_hFontIcon ); 352 | surface.SetTextColor( 0xcc, 0xcc, 0xcc, 0xcc ); 353 | surface.SetTextPos( x + m_nOffsetClipIcon, y0 + YRES(4) ); 354 | surface.DrawUnicodeChar( m_chCurTextureDataAmmo, 0 ); 355 | 356 | // blur 357 | surface.DrawColoredText( m_hFontBlur, x + m_nOffsetClipLabel, y0 + YRES(1), 0x00, 0x00, 0x00, 0xff, m_szAmmoClip ); 358 | 359 | // label 360 | surface.DrawColoredText( m_hFont, x + m_nOffsetClipLabel, y0 + YRES(1), 0xe7, 0xe7, 0xe7, 0xff, m_szAmmoClip ); 361 | 362 | if ( m_bVisibleReserve ) 363 | { 364 | x = x0 + YRES(84); 365 | local y = y0 + YRES(8.5); 366 | 367 | // blur 368 | surface.DrawColoredText( m_hFontSmallBlur, x, y, 0x00, 0x00, 0x00, 0xff, m_szAmmoReserve ); 369 | 370 | // label 371 | surface.DrawColoredText( m_hFontSmall, x, y, 0xcc, 0xcc, 0xcc, 0xff, m_szAmmoReserve ); 372 | } 373 | } 374 | 375 | if ( 0 in m_szAmmoSecondary ) 376 | { 377 | local x = x0 + YRES(18); 378 | 379 | // icon blur 380 | surface.SetTextFont( m_hFontIconBlur ); 381 | surface.SetTextColor( 0x00, 0x00, 0x00, 0xff ); 382 | surface.SetTextPos( x + m_nOffsetSecondaryIcon, y0 + YRES(4) ); 383 | surface.DrawUnicodeChar( m_chCurTextureDataAmmo2, 0 ); 384 | 385 | // icon 386 | surface.SetTextFont( m_hFontIcon ); 387 | surface.SetTextColor( 0xcc, 0xcc, 0xcc, 0xcc ); 388 | surface.SetTextPos( x + m_nOffsetSecondaryIcon, y0 + YRES(4) ); 389 | surface.DrawUnicodeChar( m_chCurTextureDataAmmo2, 0 ); 390 | 391 | // blur 392 | surface.DrawColoredText( m_hFontBlur, x, y0 + YRES(1), 0x00, 0x00, 0x00, 0xff, m_szAmmoSecondary ); 393 | 394 | // label 395 | surface.DrawColoredText( m_hFont, x, y0 + YRES(1), 0xe7, 0xe7, 0xe7, 0xff, m_szAmmoSecondary ); 396 | } 397 | } 398 | 399 | function CSGOHudWeaponAmmo::SetAmmoInClip( nAmt ) 400 | { 401 | local text = "" + nAmt; 402 | m_szAmmoClip = text; 403 | 404 | m_nOffsetClipLabel = m_nClipLabelWide - surface.GetTextWidth( m_hFont, text ); 405 | } 406 | 407 | // NOTE: In CSGO this is "/ %d" right aligned, but "/ %3d" left aligned looks good too, 408 | // also keeps the '/' in the same position 409 | function CSGOHudWeaponAmmo::SetAmmoInReserve( nAmt ) 410 | { 411 | m_szAmmoReserve = Fmt( "/ %3d", nAmt ); 412 | } 413 | 414 | function CSGOHudWeaponAmmo::SetVisible( state ) 415 | { 416 | m_bVisible = state; 417 | return self.SetVisible( state ); 418 | } 419 | -------------------------------------------------------------------------------- /mapbase/cs_hud/huddamageindicator.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | local surface = surface, FrameTime = FrameTime, 7 | CurrentViewForward = CurrentViewForward, 8 | CurrentViewRight = CurrentViewRight; 9 | 10 | const CSGOHUD_DMG_INDICATOR_BURN = 1; 11 | const CSGOHUD_DMG_INDICATOR_POISON = 2; 12 | const CSGOHUD_DMG_INDICATOR_RADIATION = 3; 13 | const CSGOHUD_DMG_INDICATOR_DEATH = 10; 14 | 15 | class CSGOHudDamageIndicator 16 | { 17 | constructor( player ) 18 | { 19 | this.player = player; 20 | } 21 | 22 | self = null 23 | player = null 24 | 25 | m_hTexVert = null 26 | m_hTexHorz = null 27 | 28 | m_nAlphaTop = 0 29 | m_nAlphaBottom = 0 30 | m_nAlphaLeft = 0 31 | m_nAlphaRight = 0 32 | 33 | m_nFlash = 0 34 | m_nFlashAlpha = 0 35 | m_hGradient = null 36 | } 37 | 38 | function CSGOHudDamageIndicator::Init() 39 | { 40 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudDamageIndicator" ); 41 | self.SetSize( XRES(640), YRES(480) ); 42 | self.SetZPos( -1 ); 43 | self.SetVisible( false ); 44 | self.SetPaintBackgroundEnabled( false ); 45 | self.SetCallback( "Paint", Paint.bindenv(this) ); 46 | 47 | m_hTexVert = surface.ValidateTexture( "panorama/images/hud/damageindicator/damage-segment_vert", true ); 48 | m_hTexHorz = surface.ValidateTexture( "panorama/images/hud/damageindicator/damage-segment_horz", true ); 49 | m_hGradient = surface.ValidateTexture( "panorama/images/masks/bottom-top-fade_additive", true ); 50 | } 51 | 52 | // NOTE: Matches SFUI, not Panorama. Panorama seems to use a different scaling 53 | function CSGOHudDamageIndicator::Paint() 54 | { 55 | local decay = ( FrameTime() * 255.0 ).tointeger(); 56 | 57 | local cx = XRES(320); 58 | local cy = YRES(240); 59 | 60 | if ( m_nFlash ) switch ( m_nFlash ) 61 | { 62 | case CSGOHUD_DMG_INDICATOR_BURN: 63 | { 64 | surface.DrawTexturedBox( m_hGradient, 0, cy, cx<<1, cy, 255, 0, 0, m_nFlashAlpha ); 65 | if ( ( m_nFlashAlpha -= decay ) <= 0 ) 66 | m_nFlash = 0; 67 | break; 68 | } 69 | case CSGOHUD_DMG_INDICATOR_POISON: 70 | { 71 | surface.DrawTexturedBox( m_hGradient, 0, cy, cx<<1, cy, 255, 236, 128, m_nFlashAlpha ); 72 | if ( ( m_nFlashAlpha -= decay ) <= 0 ) 73 | m_nFlash = 0; 74 | break; 75 | } 76 | case CSGOHUD_DMG_INDICATOR_RADIATION: 77 | { 78 | surface.DrawTexturedBox( m_hGradient, 0, cy, cx<<1, cy, 255, 255, 255, m_nFlashAlpha ); 79 | if ( ( m_nFlashAlpha -= decay ) <= 0 ) 80 | m_nFlash = 0; 81 | break; 82 | } 83 | case CSGOHUD_DMG_INDICATOR_DEATH: 84 | { 85 | // Lazy, but it works. 86 | surface.SetColor( 255, 0, 0, 50 ); 87 | surface.DrawFilledRect( 0, 0, cx<<1, cy<<1 ); 88 | return; 89 | } 90 | } 91 | 92 | local sh = YRES(64); 93 | local sw = sh << 1; 94 | 95 | surface.SetTexture( m_hTexVert ); 96 | 97 | // top 98 | local x = cx - sh; 99 | local y = cy - sh; 100 | if ( m_nAlphaTop ) 101 | { 102 | surface.SetColor( 255, 255, 255, m_nAlphaTop ); 103 | surface.DrawTexturedRect( x, y, sw, sh ); 104 | 105 | if ( ( m_nAlphaTop -= decay ) < 0 ) 106 | m_nAlphaTop = 0; 107 | } 108 | 109 | // bottom 110 | y = cy; 111 | if ( m_nAlphaBottom ) 112 | { 113 | surface.SetColor( 255, 255, 255, m_nAlphaBottom ); 114 | surface.DrawTexturedSubRect( x, y, x + sw, y + sh, 0., 1., 1., 0. ); 115 | 116 | if ( ( m_nAlphaBottom -= decay ) < 0 ) 117 | m_nAlphaBottom = 0; 118 | } 119 | 120 | surface.SetTexture( m_hTexHorz ); 121 | 122 | // left 123 | y = cy - sh; 124 | if ( m_nAlphaLeft ) 125 | { 126 | surface.SetColor( 255, 255, 255, m_nAlphaLeft ); 127 | surface.DrawTexturedRect( x, y, sh, sw ); 128 | 129 | if ( ( m_nAlphaLeft -= decay ) < 0 ) 130 | m_nAlphaLeft = 0; 131 | } 132 | 133 | // right 134 | x = cx; 135 | if ( m_nAlphaRight ) 136 | { 137 | surface.SetColor( 255, 255, 255, m_nAlphaRight ); 138 | surface.DrawTexturedSubRect( x, y, x + sh, y + sw, 1., 0., 0., 1. ); 139 | 140 | if ( ( m_nAlphaRight -= decay ) < 0 ) 141 | m_nAlphaRight = 0; 142 | } 143 | 144 | if ( !(m_nAlphaTop|m_nAlphaBottom|m_nAlphaLeft|m_nAlphaRight|m_nFlash) ) 145 | { 146 | self.SetVisible( false ); 147 | } 148 | } 149 | 150 | function CSGOHudDamageIndicator::DamageTaken( bits, origin ) 151 | { 152 | if ( player.GetHealth() <= 0 ) 153 | { 154 | m_nFlash = CSGOHUD_DMG_INDICATOR_DEATH; 155 | } 156 | // Single time impact effect. HL2 specific, doesn't exist in CSGO 157 | // DROWN/CRUSH/PLASMA are handled in CBasePlayer::DamageEffect() 158 | else if ( bits & CSGOHUD_DMG_SCR_FX ) 159 | { 160 | if ( bits & DMG_BURN ) 161 | { 162 | m_nFlash = CSGOHUD_DMG_INDICATOR_BURN; 163 | m_nFlashAlpha = 127; 164 | } 165 | else if ( bits & DMG_POISON ) 166 | { 167 | m_nFlash = CSGOHUD_DMG_INDICATOR_POISON; 168 | m_nFlashAlpha = 127; 169 | } 170 | else if ( bits & DMG_RADIATION ) 171 | { 172 | m_nFlash = CSGOHUD_DMG_INDICATOR_RADIATION; 173 | m_nFlashAlpha = 127; 174 | } 175 | } 176 | 177 | local vecDelta = origin.Subtract( player.GetOrigin() ); 178 | local flDist = vecDelta.Norm(); 179 | 180 | if ( flDist < 42.0 ) 181 | { 182 | m_nAlphaTop = m_nAlphaBottom = m_nAlphaRight = m_nAlphaLeft = 255; 183 | return self.SetVisible( true ); 184 | } 185 | 186 | local viewForward = CurrentViewForward(), viewRight = CurrentViewRight(); 187 | // Keep for displaying damage from above 188 | //viewForward.z = 0.0; 189 | 190 | local dot = vecDelta.Dot( viewForward ); 191 | if ( dot > 0.32 ) 192 | { 193 | dot = ( dot * 255.0 ).tointeger(); 194 | if ( m_nAlphaTop < dot ) 195 | m_nAlphaTop = dot; 196 | } 197 | else if ( dot < -0.32 ) 198 | { 199 | dot = ( dot * -255.0 ).tointeger(); 200 | if ( m_nAlphaBottom < dot ) 201 | m_nAlphaBottom = dot; 202 | } 203 | 204 | dot = vecDelta.Dot( viewRight ); 205 | if ( dot > 0.32 ) 206 | { 207 | dot = ( dot * 255.0 ).tointeger(); 208 | if ( m_nAlphaRight < dot ) 209 | m_nAlphaRight = dot; 210 | } 211 | else if ( dot < -0.32 ) 212 | { 213 | dot = ( dot * -255.0 ).tointeger(); 214 | if ( m_nAlphaLeft < dot ) 215 | m_nAlphaLeft = dot; 216 | } 217 | 218 | return self.SetVisible( true ); 219 | } 220 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudhealtharmor.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface, Entities = Entities; 8 | 9 | local kClrNormal = [ surface, 0xe7, 0xe7, 0xe7, 0xff ]; 10 | local kClrLow = [ surface, 0xff, 0x00, 0x00, 0xdd ]; 11 | 12 | const kHudHealthPanelHeight = 22; 13 | 14 | 15 | class CSGOHudHealthArmor 16 | { 17 | constructor( player ) 18 | { 19 | this.player = player; 20 | } 21 | 22 | self = null 23 | player = null 24 | 25 | m_bDrawArmor = true 26 | 27 | m_flMaxHealth = 100.0 28 | m_nHealth = -1 29 | m_flHealth = 0.0 30 | m_szHealth = "0" 31 | 32 | m_flMaxArmor = 100.0 33 | m_nArmor = -1 34 | m_flArmor = 0.0 35 | m_szArmor = "0" 36 | 37 | m_clrHealthBar = null 38 | 39 | m_nHealthWarningThreshold = 0 40 | 41 | m_hFontLarge = null 42 | m_hFontLargeBlur = null 43 | m_hFontSm = null 44 | m_hFontSmBlur = null 45 | 46 | m_hFontHealth = null 47 | m_hFontHealthBlur = null 48 | m_hFontArmor = null 49 | m_hFontArmorBlur = null 50 | 51 | m_hTexHealth = null 52 | m_hTexArmor = null 53 | 54 | m_nOffsetHealthLabelX = 0 55 | m_nOffsetHealthLabelY = 0 56 | m_nOffsetArmorLabelX = 0 57 | m_nOffsetArmorLabelY = 0 58 | m_nLabelWide = 0 59 | } 60 | 61 | function CSGOHudHealthArmor::Init() 62 | { 63 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudHealthArmor" ); 64 | self.SetVisible( false ); 65 | self.SetPaintBackgroundEnabled( false ); 66 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 67 | self.SetCallback( "OnTick", OnTick.bindenv(this) ); 68 | self.SetCallback( "Paint", Paint.bindenv(this) ); 69 | self.AddTickSignal( 100 ); 70 | 71 | m_hFontLarge = surface.GetFont( "hud-HA-text", true ); 72 | m_hFontLargeBlur = surface.GetFont( "hud-HA-text-blur", true ); 73 | 74 | m_hFontSm = surface.GetFont( "hud-HA-text-medium", true ); 75 | m_hFontSmBlur = surface.GetFont( "hud-HA-text-medium-blur", true ); 76 | 77 | m_hTexHealth = surface.ValidateTexture( "panorama/images/icons/ui/health", true ); 78 | m_hTexArmor = surface.ValidateTexture( "panorama/images/icons/ui/shield", true ); 79 | 80 | m_clrHealthBar = kClrNormal; 81 | } 82 | 83 | function CSGOHudHealthArmor::PerformLayout() 84 | { 85 | // margin-left 86 | self.SetPos( YRES(3.15), 0 ); 87 | self.SetSize( XRES(640) - self.GetXPos(), YRES(480) ); 88 | 89 | m_nLabelWide = surface.GetCharacterWidth( m_hFontLarge, '0' ) * 3; 90 | 91 | // Recalculate 92 | m_nHealth = m_hFontHealth = m_hFontArmor = -1; 93 | OnTick(); 94 | SetArmor( m_nArmor ); 95 | } 96 | 97 | local ThinkRestoreColour = function(_) 98 | { 99 | m_clrHealthBar = kClrNormal; 100 | } 101 | 102 | function CSGOHudHealthArmor::SetArmor( nArmor ) 103 | { 104 | m_nArmor = nArmor; 105 | m_flArmor = nArmor / m_flMaxArmor; 106 | 107 | if ( m_flArmor > 1.0 ) 108 | m_flArmor = 1.0; 109 | 110 | if ( nArmor < 1000 ) 111 | { 112 | if ( m_hFontArmor != m_hFontLarge ) 113 | { 114 | m_hFontArmor = m_hFontLarge; 115 | m_hFontArmorBlur = m_hFontLargeBlur; 116 | m_nOffsetArmorLabelY = ( YRES(kHudHealthPanelHeight) - surface.GetFontTall( m_hFontArmor ) ) >> 1; 117 | } 118 | } 119 | else 120 | { 121 | if ( m_hFontArmor != m_hFontSm ) 122 | { 123 | m_hFontArmor = m_hFontSm; 124 | m_hFontArmorBlur = m_hFontSmBlur; 125 | m_nOffsetArmorLabelY = ( YRES(kHudHealthPanelHeight) - surface.GetFontTall( m_hFontArmor ) ) >> 1; 126 | } 127 | } 128 | 129 | local text = m_szArmor = "" + nArmor; 130 | m_nOffsetArmorLabelX = ( m_nLabelWide - surface.GetTextWidth( m_hFontArmor, text ) ) >> 1; 131 | } 132 | 133 | function CSGOHudHealthArmor::OnTick() 134 | { 135 | local nHealth = player.GetHealth(); 136 | 137 | if ( nHealth < 0 ) 138 | nHealth = 0; 139 | 140 | if ( nHealth == m_nHealth ) 141 | return; 142 | 143 | // flash the health bar red when hurt 144 | if ( nHealth < m_nHealth && nHealth > m_nHealthWarningThreshold ) 145 | { 146 | m_clrHealthBar = kClrLow; 147 | Entities.First().SetContextThink( "CSGOHudHealthArmor", ThinkRestoreColour.bindenv(this), 1.0 ); 148 | } 149 | 150 | m_nHealth = nHealth; 151 | m_flHealth = nHealth / m_flMaxHealth; 152 | 153 | if ( m_flHealth > 1.0 ) 154 | m_flHealth = 1.0; 155 | 156 | if ( nHealth < 1000 ) 157 | { 158 | if ( m_hFontHealth != m_hFontLarge ) 159 | { 160 | m_hFontHealth = m_hFontLarge; 161 | m_hFontHealthBlur = m_hFontLargeBlur; 162 | m_nOffsetHealthLabelY = ( YRES(kHudHealthPanelHeight) - surface.GetFontTall( m_hFontHealth ) ) >> 1; 163 | } 164 | } 165 | else 166 | { 167 | if ( m_hFontHealth != m_hFontSm ) 168 | { 169 | m_hFontHealth = m_hFontSm; 170 | m_hFontHealthBlur = m_hFontSmBlur; 171 | m_nOffsetHealthLabelY = ( YRES(kHudHealthPanelHeight) - surface.GetFontTall( m_hFontHealth ) ) >> 1; 172 | } 173 | } 174 | 175 | local text = m_szHealth = "" + nHealth; 176 | m_nOffsetHealthLabelX = ( m_nLabelWide - surface.GetTextWidth( m_hFontHealth, text ) ) >> 1; 177 | } 178 | 179 | function CSGOHudHealthArmor::DrawBackground( bHealthThreshold, height, y0 ) 180 | { 181 | local flAlpha = CSHud.m_flBackgroundAlpha; 182 | 183 | if ( m_bDrawArmor ) 184 | { 185 | local width_a = YRES(82); 186 | local width_h = YRES(87); 187 | local x = 0; 188 | local w = width_h / 10; 189 | 190 | if ( bHealthThreshold ) 191 | { 192 | // health 193 | surface.SetColor( 0x77, 0x00, 0x00, flAlpha * 0xEE ); 194 | 195 | surface.DrawFilledRectFade( x, y0, w, height, 0x00, 0xFF, true ); 196 | x += w; 197 | w = width_h - w; 198 | surface.DrawFilledRectFade( x, y0, w, height, 0xFF, 0xFF, true ); 199 | 200 | // armor 201 | surface.SetColor( 0x00, 0x00, 0x00, flAlpha * 0xcc ); 202 | 203 | x += w; 204 | w = width_a * 40 / 100; 205 | surface.DrawFilledRect( x, y0, w, height ); 206 | x += w; 207 | w = width_a - w; 208 | return surface.DrawFilledRectFade( x, y0, w, height, 0xFF, 0x00, true ); 209 | } 210 | else 211 | { 212 | surface.SetColor( 0x00, 0x00, 0x00, flAlpha * 0xcc ); 213 | 214 | // health 215 | surface.DrawFilledRectFade( x, y0, w, height, 0x00, 0xEE, true ); 216 | x += w; 217 | w = width_h - w; 218 | surface.DrawFilledRectFade( x, y0, w, height, 0xEE, 0xFF, true ); 219 | 220 | // armor 221 | x += w; 222 | w = width_a * 40 / 100; 223 | surface.DrawFilledRect( x, y0, w, height ); 224 | x += w; 225 | w = width_a - w; 226 | return surface.DrawFilledRectFade( x, y0, w, height, 0xFF, 0x00, true ); 227 | } 228 | } 229 | else 230 | { 231 | if ( bHealthThreshold ) 232 | { 233 | surface.SetColor( 0x77, 0x00, 0x00, flAlpha * 0xEE ); 234 | } 235 | else 236 | { 237 | surface.SetColor( 0x00, 0x00, 0x00, flAlpha * 0xcc ); 238 | } 239 | 240 | local x = 0; 241 | local w = YRES(8.7); 242 | surface.DrawFilledRectFade( x, y0, w, height, 0x00, 0xff, true ); 243 | x += w; 244 | w = YRES(32.8); 245 | surface.DrawFilledRect( x, y0, w, height ); 246 | x += w; 247 | w = YRES(49.2); 248 | return surface.DrawFilledRectFade( x, y0, w, height, 0xff, 0x00, true ); 249 | } 250 | } 251 | 252 | // 253 | // NOTE: 254 | // There is no progress bar drop shadow 255 | // Positions are not pixel perfect on every resolution 256 | // 257 | function CSGOHudHealthArmor::Paint() 258 | { 259 | local height = YRES(kHudHealthPanelHeight); 260 | local y0 = YRES(480) - height; 261 | 262 | local bar_w = YRES(32.9); 263 | local bar_h = YRES(4.25); 264 | local bar_y = YRES(10) + y0; 265 | local icon_y = YRES(7) + y0; 266 | { 267 | local icon_s = YRES(8.75); 268 | local icon_x = YRES(8.5); 269 | local bar_x = YRES(48); 270 | local bar_progress = (bar_w * m_flHealth + 0.71).tointeger(); 271 | local label_x = YRES(19) + m_nOffsetHealthLabelX; 272 | local label_y = m_nOffsetHealthLabelY + y0; 273 | 274 | if ( m_nHealth > m_nHealthWarningThreshold ) 275 | { 276 | DrawBackground( false, height, y0 ); 277 | 278 | // health bar 279 | surface.SetColor.acall( m_clrHealthBar ); 280 | surface.DrawFilledRect( bar_x, bar_y, bar_progress, bar_h ); 281 | 282 | // health icon 283 | surface.DrawTexturedBox( m_hTexHealth, icon_x, icon_y, icon_s, icon_s, 0xcc, 0xcc, 0xcc, 165 ); 284 | 285 | // health label blur 286 | surface.DrawColoredText( m_hFontHealthBlur, label_x, label_y, 0x00, 0x00, 0x00, 0xff, m_szHealth ); 287 | } 288 | else 289 | { 290 | DrawBackground( true, height, y0 ); 291 | 292 | // health bar 293 | surface.SetColor.acall( kClrLow ); 294 | surface.DrawFilledRect( bar_x, bar_y, bar_progress, bar_h ); 295 | 296 | // health icon 297 | surface.DrawTexturedBox( m_hTexHealth, icon_x, icon_y, icon_s, icon_s, 0xff, 0x00, 0x00, 165 ); 298 | 299 | // label blur 300 | // NOTE: Glow is too weak, draw it twice 301 | surface.DrawColoredText( m_hFontHealthBlur, label_x, label_y, 0xff, 0x00, 0x00, 0xff, m_szHealth ); 302 | surface.DrawColoredText( m_hFontHealthBlur, label_x, label_y, 0xff, 0x00, 0x00, 0xff, m_szHealth ); 303 | } 304 | 305 | // health bar 306 | if ( m_flHealth < 1.0 ) 307 | { 308 | surface.SetColor( 0x66, 0x66, 0x66, 0x99 ); 309 | surface.DrawFilledRect( bar_x + bar_progress, bar_y, bar_w - bar_progress, bar_h ); 310 | } 311 | 312 | // bar outline 313 | surface.SetColor( 0x88, 0x88, 0x88, 0x7f ); 314 | surface.DrawOutlinedRect( bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, 1 ); 315 | 316 | // health label 317 | surface.DrawColoredText( m_hFontHealth, label_x, label_y, 0xe7, 0xe7, 0xe7, 0xff, m_szHealth ); 318 | } 319 | 320 | if ( m_bDrawArmor ) 321 | { 322 | local icon_s = YRES(8); 323 | local icon_x = YRES(93.5); 324 | local bar_x = YRES(133.25); 325 | local bar_progress = (bar_w * m_flArmor + 0.71).tointeger(); 326 | local label_x = YRES(104) + m_nOffsetArmorLabelX; 327 | local label_y = m_nOffsetArmorLabelY + y0; 328 | 329 | // armour bar 330 | surface.SetColor( 0xe7, 0xe7, 0xe7, 0xff ); 331 | surface.DrawFilledRect( bar_x, bar_y, bar_progress, bar_h ); 332 | 333 | if ( m_flArmor < 1.0 ) 334 | { 335 | surface.SetColor( 0x66, 0x66, 0x66, 0x99 ); 336 | surface.DrawFilledRect( bar_x + bar_progress, bar_y, bar_w - bar_progress, bar_h ); 337 | } 338 | 339 | // bar outline 340 | surface.SetColor( 0x88, 0x88, 0x88, 0x7f ); 341 | surface.DrawOutlinedRect( bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, 1 ); 342 | 343 | // armour icon 344 | surface.DrawTexturedBox( m_hTexArmor, icon_x, icon_y, icon_s, icon_s, 0xcc, 0xcc, 0xcc, 165 ); 345 | 346 | // armour label blur 347 | surface.DrawColoredText( m_hFontArmorBlur, label_x, label_y, 0x00, 0x00, 0x00, 0xff, m_szArmor ); 348 | 349 | // armour label 350 | surface.DrawColoredText( m_hFontArmor, label_x, label_y, 0xe7, 0xe7, 0xe7, 0xff, m_szArmor ); 351 | } 352 | } 353 | 354 | local CONST = getconsttable(); 355 | { 356 | delete CONST.kHudHealthPanelHeight; 357 | } 358 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudhinttext.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | local surface = surface, Time = Time, SimpleSpline = SimpleSpline, split = split, 7 | Entities = Entities, Localize = Localize; 8 | 9 | const kHudHintDisplayTime = 4.0; 10 | const kHudHintEndYPos = 91; 11 | const kHudHintIconSize = 13; 12 | const kHudHintIconMargin = 3; 13 | const kHudHintTextPad = 2; 14 | 15 | class CSGOHudHintText 16 | { 17 | self = null 18 | 19 | m_bFading = false 20 | 21 | m_flStartTime = 0.0 22 | m_nYPos = 0 23 | m_nTextWidth = 0 24 | m_nTotalHeight = 0 25 | m_nEndYPos = 0 26 | m_Lines = null 27 | 28 | m_hFont = null 29 | m_hIcon = null 30 | m_hIconInfo = null 31 | m_hIconAlert = null 32 | } 33 | 34 | function CSGOHudHintText::Init() 35 | { 36 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudHintText" ); 37 | self.SetSize( XRES(640), YRES(480) ); 38 | self.SetZPos( 10 ); 39 | self.SetVisible( false ); 40 | self.SetPaintBackgroundEnabled( false ); 41 | self.SetCallback( "Paint", Paint.bindenv(this) ); 42 | 43 | m_hFont = surface.GetFont( "hud-hint__text", true ); 44 | m_hIconInfo = surface.ValidateTexture( "panorama/images/icons/ui/info", true ); 45 | m_hIconAlert = surface.ValidateTexture( "panorama/images/icons/ui/alert", true ); 46 | 47 | m_Lines = []; 48 | 49 | ListenToGameEvent( "player_hintmessage", FireGameEvent.bindenv(this), "CSGOHudHintText" ); 50 | } 51 | 52 | function CSGOHudHintText::FireGameEvent( event ) 53 | { 54 | Display( event.hintmessage ); 55 | } 56 | 57 | function CSGOHudHintText::Display( msg ) 58 | { 59 | if ( !( 0 in msg ) ) 60 | return SetVisible( false ); 61 | 62 | if ( msg[0] == '#' ) 63 | msg = Localize.Find( msg ); 64 | 65 | local width = 0; 66 | local height = 1; 67 | 68 | if ( msg.find("\n") == null ) 69 | { 70 | width = surface.GetTextWidth( m_hFont, msg ); 71 | 72 | m_Lines.clear(); 73 | m_Lines.append( msg ); 74 | } 75 | else 76 | { 77 | local lines = split( msg, "\n" ); 78 | foreach ( s in lines ) 79 | { 80 | local w = surface.GetTextWidth( m_hFont, s ); 81 | if ( w > width ) 82 | { 83 | width = w; 84 | } 85 | } 86 | 87 | height = lines.len(); 88 | m_Lines = lines; 89 | } 90 | 91 | height *= surface.GetFontTall( m_hFont ); 92 | height += YRES(kHudHintIconSize + kHudHintIconMargin + kHudHintTextPad*2); 93 | 94 | m_nTextWidth = width; 95 | m_nTotalHeight = height; 96 | 97 | // This isn't adjusted in csgo, the text beyond is not visible there 98 | if ( YRES(kHudHintEndYPos) + height < YRES(240) ) 99 | { 100 | m_nEndYPos = YRES(kHudHintEndYPos); 101 | } 102 | else 103 | { 104 | m_nEndYPos = YRES(240) - height - surface.GetFontTall( m_hFont ); 105 | } 106 | 107 | return SetVisible( true ); 108 | } 109 | 110 | function CSGOHudHintText::Paint() 111 | { 112 | local width = YRES(304); 113 | local cx = XRES(320); 114 | local x0 = cx - ( width >> 1 ) - YRES(1); 115 | local y0 = m_nYPos; 116 | local height = m_nTotalHeight; 117 | 118 | // background 119 | { 120 | surface.SetColor( 0x00, 0x00, 0x00, 0xff ); 121 | 122 | local w10 = width / 10; 123 | local w50 = width / 4; 124 | local w25 = w50 - w10; 125 | local x = x0; 126 | 127 | surface.DrawFilledRectFade( x , y0, w10, height, 0x00, 0x0d, true ); 128 | surface.DrawFilledRectFade( x += w10, y0, w25, height, 0x0d, 0x99, true ); 129 | surface.DrawFilledRectFade( x += w25, y0, w50, height, 0x99, 0x80, true ); 130 | surface.DrawFilledRectFade( x += w50, y0, w50, height, 0x80, 0x99, true ); 131 | surface.DrawFilledRectFade( x += w50, y0, w25, height, 0x99, 0x0d, true ); 132 | surface.DrawFilledRectFade( x + w25, y0, w10, height, 0x0d, 0x00, true ); 133 | } 134 | 135 | { 136 | // hrTop 137 | local w05 = width / 20; 138 | local w50 = width / 2 - w05; 139 | local x = x0; 140 | 141 | surface.DrawFilledRectFade( x , y0, w05, 1, 0x00, 0x12, true ); 142 | surface.DrawFilledRectFade( x += w05, y0, w50, 1, 0x12, 0x80, true ); 143 | surface.DrawFilledRectFade( x += w50, y0, w50, 1, 0x80, 0x12, true ); 144 | surface.DrawFilledRectFade( x + w50, y0, w05, 1, 0x12, 0x00, true ); 145 | 146 | // hrBot 147 | x = x0; 148 | local y = y0 + height - 1; 149 | 150 | surface.DrawFilledRectFade( x , y, w05, 1, 0x00, 0x12, true ); 151 | surface.DrawFilledRectFade( x += w05, y, w50, 1, 0x12, 0x80, true ); 152 | surface.DrawFilledRectFade( x += w50, y, w50, 1, 0x80, 0x12, true ); 153 | surface.DrawFilledRectFade( x + w50, y, w05, 1, 0x12, 0x00, true ); 154 | } 155 | 156 | // icon 157 | local iconSize = YRES(kHudHintIconSize); 158 | local y = y0 + YRES(kHudHintIconMargin); 159 | { 160 | // This is centered unlike in CSGO 161 | local x = cx - ( iconSize >> 1 ); 162 | // No shadow in csgo 163 | surface.DrawTexturedBox( m_hIcon, x, y, iconSize, iconSize, 0xff, 0xff, 0xff, 0xff ); 164 | } 165 | 166 | // text 167 | { 168 | local x = cx - ( m_nTextWidth >> 1 ); 169 | y += iconSize + YRES(kHudHintTextPad); 170 | 171 | surface.SetTextFont( m_hFont ); 172 | local tall = surface.GetFontTall( m_hFont ); 173 | foreach ( line in m_Lines ) 174 | { 175 | // shadow 176 | surface.SetTextPos( x+1, y+1 ); 177 | surface.SetTextColor( 0x00, 0x00, 0x00, 0x88 ); 178 | surface.DrawText( line, 0 ); 179 | 180 | // text 181 | surface.SetTextPos( x, y ); 182 | surface.SetTextColor( 0xff, 0xff, 0xff, 0xff ); 183 | surface.DrawText( line, 0 ); 184 | 185 | y += tall; 186 | } 187 | } 188 | } 189 | 190 | function CSGOHudHintText::Think(_) 191 | { 192 | local dt = ( Time() - m_flStartTime ); 193 | 194 | if ( m_bFading ) 195 | { 196 | local startpos = YRES(kHudHintEndYPos << 1); 197 | 198 | local t = dt / 0.2; 199 | if ( t < 1.0 ) 200 | { 201 | m_nYPos = YRES(240) + startpos + ( m_nEndYPos - startpos ) * SimpleSpline(t); 202 | self.SetAlpha( 255 * t ); 203 | } 204 | else 205 | { 206 | m_nYPos = YRES(240) + m_nEndYPos; 207 | self.SetAlpha( 255 ); 208 | m_bFading = false; 209 | } 210 | } 211 | else 212 | { 213 | if ( dt > kHudHintDisplayTime ) 214 | { 215 | self.SetVisible( false ); 216 | return -1; 217 | } 218 | } 219 | 220 | return 0.0; 221 | } 222 | 223 | function CSGOHudHintText::SetVisible( state, priority = false ) 224 | { 225 | if ( state ) 226 | { 227 | if ( priority ) 228 | { 229 | // TODO: Set colour and the "Alert" text 230 | m_hIcon = m_hIconAlert; 231 | } 232 | else 233 | { 234 | m_hIcon = m_hIconInfo; 235 | } 236 | 237 | m_flStartTime = Time(); 238 | 239 | if ( !m_bFading && !self.IsVisible() ) 240 | { 241 | m_bFading = true; 242 | self.SetVisible( true ); 243 | self.SetAlpha( 0 ); 244 | m_nYPos = YRES(240 + (kHudHintEndYPos << 1)); 245 | return Entities.First().SetContextThink( "CSGOHudHintText.FadeIn", Think.bindenv(this), 0.0 ); 246 | } 247 | } 248 | else 249 | { 250 | self.SetVisible( false ); 251 | return Entities.First().SetContextThink( "CSGOHudHintText.FadeIn", null, 0.0 ); 252 | } 253 | } 254 | 255 | { 256 | local CONST = getconsttable(); 257 | delete CONST.kHudHintDisplayTime; 258 | delete CONST.kHudHintEndYPos; 259 | delete CONST.kHudHintIconSize; 260 | delete CONST.kHudHintIconMargin; 261 | delete CONST.kHudHintTextPad; 262 | } 263 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudlocator.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface; 8 | local MainViewOrigin = MainViewOrigin, MainViewAngles = MainViewAngles, 9 | cos = cos, atan2 = atan2, AngleDiff = AngleDiff, fabs = fabs; 10 | 11 | 12 | class CSGOHudLocator 13 | { 14 | self = null 15 | m_bVisible = false 16 | 17 | // HL2 has only one and hardcoded locator position and texture 18 | m_vecLocatorOrigin = null 19 | m_hTargetTexture = 0 20 | } 21 | 22 | function CSGOHudLocator::Init() 23 | { 24 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudLocator" ) 25 | self.SetSize( XRES(640), YRES(480) ); 26 | self.SetVisible( m_bVisible ); 27 | self.SetPaintBackgroundEnabled( false ); 28 | self.SetCallback( "Paint", Paint.bindenv(this) ); 29 | 30 | m_vecLocatorOrigin = Vector(); 31 | } 32 | 33 | function CSGOHudLocator::Paint() 34 | { 35 | local width = YRES(64); 36 | local height = YRES(22); 37 | 38 | local scrh = YRES(480); 39 | 40 | local x0 = XRES(326); 41 | local y0 = scrh - height; 42 | 43 | // bg 44 | { 45 | local flAlpha = CSHud.m_flBackgroundAlpha; 46 | local w = width / 4; 47 | surface.SetColor( 0x00, 0x00, 0x00, 0xcc * flAlpha ); 48 | surface.DrawFilledRectFade( x0, y0, w, height, 0x00, 0xff, true ); 49 | local x = x0 + w; 50 | surface.DrawFilledRect( x, y0, w + w, height ); 51 | surface.DrawFilledRectFade( x + w + w, y0, w, height, 0xff, 0x00, true ); 52 | } 53 | 54 | local viewYaw = MainViewAngles().y; 55 | 56 | // Compass ticks 57 | { 58 | surface.SetColor( 0xe7, 0xe7, 0xe7, 0x40 ); 59 | 60 | viewYaw = -viewYaw; // flip for compass 61 | 62 | local longTick = YRES(16); 63 | local shortTick = YRES(18); 64 | local flStep = 22.5; 65 | local flLimit = 100.; 66 | local flStart = -180.; 67 | local flEnd = 180.; 68 | 69 | local tall = true; 70 | for ( local ang = flStart; ang <= flEnd; ang += flStep ) 71 | { 72 | tall = !tall; 73 | 74 | local dt = AngleDiff( viewYaw, ang ) / 2.0; 75 | if ( dt > flLimit || dt < -flLimit ) 76 | continue; 77 | 78 | local xpos = x0 + ( cos((dt+90.0)*DEG2RAD) + 1.0 ) * ( width / 2 ); 79 | 80 | if ( tall ) 81 | { 82 | surface.DrawLine( xpos, y0+longTick, xpos, scrh ); 83 | } 84 | else 85 | { 86 | surface.DrawLine( xpos, y0+shortTick, xpos, scrh ); 87 | } 88 | } 89 | } 90 | 91 | { 92 | viewYaw = -viewYaw; // flip back 93 | 94 | local vecDelta = MainViewOrigin().Subtract( m_vecLocatorOrigin ).Multiply(-1); 95 | local yawDelta = atan2( vecDelta.y, vecDelta.x ) * RAD2DEG; 96 | local yawDiff = AngleDiff( viewYaw, yawDelta ) / 2.0; 97 | 98 | // Make it look like it's floating in front of the compass 99 | local margin = YRES(4); 100 | 101 | // Texture is assumed square 102 | local texTall = YRES(38); 103 | local texWide = ( 1.0 - fabs(yawDiff) / 90.0 ) * texTall; 104 | local xpos = x0 + ( cos((yawDiff-90.0)*DEG2RAD) + 1.0 ) * ( width / 2 + margin ) - texWide / 2.0; 105 | 106 | surface.DrawTexturedBox( m_hTargetTexture, xpos-margin, y0-YRES(12), texWide, texTall, 0xe7, 0xe7, 0xe7, 0x99 ); 107 | } 108 | } 109 | 110 | function CSGOHudLocator::SetVisible( state ) 111 | { 112 | m_bVisible = state; 113 | return self.SetVisible( state ); 114 | } 115 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudpoisondamageindicator.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | local surface = surface, Time = Time, cos = cos; 7 | 8 | 9 | class CSGOHudPoisonDamageIndicator 10 | { 11 | self = null 12 | 13 | m_nState = 0 14 | m_flFadeStart = 0.0; 15 | m_nLastAlpha = 0; 16 | m_hTexture = null 17 | } 18 | 19 | function CSGOHudPoisonDamageIndicator::Init() 20 | { 21 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudPoisonDamageIndicator" ); 22 | self.SetZPos( -2 ); 23 | self.SetSize( XRES(640), YRES(480) ); 24 | self.SetVisible( false ); 25 | self.SetPaintBackgroundEnabled( false ); 26 | self.SetCallback( "Paint", Paint.bindenv(this) ); 27 | 28 | m_hTexture = surface.ValidateTexture( "panorama/images/masks/bottom-top-fade_additive", true ); 29 | } 30 | 31 | function CSGOHudPoisonDamageIndicator::Paint() 32 | { 33 | local a = 0.0; 34 | switch ( m_nState ) 35 | { 36 | // Pulse 37 | case 0: 38 | { 39 | a = ( cos( ( Time() - m_flFadeStart ) * PI * 2.0 ) * 0.5 + 0.5 ) * ( 14.0 - 7.0 ) + 7.0; 40 | break; 41 | } 42 | // Fade in 43 | case 1: 44 | { 45 | local t = ( Time() - m_flFadeStart ) / 0.5; 46 | a = t * 14.0; 47 | if ( a >= 14.0 ) 48 | { 49 | m_nState = 0; 50 | m_flFadeStart = Time(); 51 | } 52 | break; 53 | } 54 | // Fade out 55 | case 2: 56 | { 57 | local t = 1.0 - ( Time() - m_flFadeStart ) / 0.5; 58 | a = t * m_nLastAlpha; 59 | if ( a <= 0.0 ) 60 | { 61 | self.SetVisible( false ); 62 | return; 63 | } 64 | break; 65 | } 66 | } 67 | 68 | surface.DrawTexturedBox( m_hTexture, 0, YRES(320), XRES(640), YRES(160), 255, 236, 128, a ); 69 | } 70 | 71 | function CSGOHudPoisonDamageIndicator::SetVisible( state ) 72 | { 73 | if ( state ) 74 | { 75 | m_nState = 1; 76 | m_flFadeStart = Time(); 77 | self.SetVisible( true ); 78 | } 79 | else 80 | { 81 | m_nLastAlpha = ( cos( ( Time() - m_flFadeStart ) * PI * 2.0 ) * 0.5 + 0.5 ) * ( 14.0 - 7.0 ) + 7.0; 82 | m_nState = 2; 83 | m_flFadeStart = Time(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudscope.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface, NetProps = NetProps, 8 | RemapValClamped = RemapValClamped, SimpleSplineRemapValClamped = SimpleSplineRemapValClamped; 9 | 10 | 11 | class CCSHudScope 12 | { 13 | constructor( player ) 14 | { 15 | this.player = player; 16 | } 17 | 18 | self = null 19 | player = null 20 | 21 | m_bVisible = false 22 | 23 | m_hScopeArc = null 24 | m_hScopeLens = null 25 | m_hScopeBlur = null 26 | m_hScopeBlurHorz = null 27 | 28 | m_nBlurWidth = 0 29 | } 30 | 31 | function CCSHudScope::Init() 32 | { 33 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSHudScope" ); 34 | self.SetSize( XRES(640), YRES(480) ); 35 | self.SetZPos( -101 ); 36 | self.SetVisible( m_bVisible ); 37 | self.SetPaintBackgroundEnabled( false ); 38 | self.SetCallback( "Paint", Paint.bindenv(this) ); 39 | 40 | m_hScopeArc = surface.ValidateTexture( "sprites/scope_arc", true ); 41 | m_hScopeLens = surface.ValidateTexture( "overlays/scope_lens", true ); 42 | m_hScopeBlur = surface.ValidateTexture( "sprites/scope_line_blur", true ); 43 | m_hScopeBlurHorz = surface.ValidateTexture( "sprites/scope_line_blur_horz", true ); 44 | 45 | m_nBlurWidth = surface.GetTextureWide( m_hScopeBlur ); 46 | } 47 | 48 | // NOTE: Blur logic is a rough approximation, and view bob doesn't exist 49 | // There is no inaccuracy in HL2 anyway, this is all visual 50 | function CCSHudScope::Paint() 51 | { 52 | local wide = XRES(640); 53 | local tall = YRES(480); 54 | local wideHalf = wide >> 1; 55 | local tallHalf = tall >> 1; 56 | local texTall = tallHalf; 57 | local texWide = texTall; 58 | local x0 = wideHalf - texWide; 59 | 60 | surface.DrawTexturedBox( m_hScopeLens, x0, 0, tall, tall, 0, 0, 0, 195 ); 61 | 62 | // Draw the crosshair 63 | local speed = NetProps.GetPropVector( player, "m_vecVelocity" ).Length(); 64 | if ( speed > 8.0 ) 65 | { 66 | local a = 0.0, w = 0.0; 67 | 68 | if ( speed > 48.0 ) 69 | { 70 | a = RemapValClamped( speed, 48.0, 150.0, 160.0, 95.0 ); 71 | w = SimpleSplineRemapValClamped( speed, 48.0, 150.0, m_nBlurWidth, m_nBlurWidth * 2 ); 72 | } 73 | else 74 | { 75 | a = RemapValClamped( speed, 8.0, 48.0, 200.0, 160.0 ); 76 | w = SimpleSplineRemapValClamped( speed, 8.0, 48.0, 2.0, m_nBlurWidth ); 77 | } 78 | 79 | surface.SetColor( 0, 0, 0, a ); 80 | 81 | surface.SetTexture( m_hScopeBlur ); 82 | surface.DrawTexturedRect( wideHalf - w * 0.5, 0, w, tall ); 83 | surface.SetTexture( m_hScopeBlurHorz ); 84 | surface.DrawTexturedRect( 0, tallHalf - w * 0.5, wide, w ); 85 | 86 | surface.SetColor( 0, 0, 0, 255 ); 87 | } 88 | // Lines only 89 | else 90 | { 91 | surface.SetColor( 0, 0, 0, 255 ); 92 | surface.DrawLine( wideHalf, 0, wideHalf, tall ); 93 | surface.DrawLine( 0, tallHalf, wide, tallHalf ); 94 | } 95 | 96 | // Draw the scope 97 | surface.SetTexture( m_hScopeArc ); 98 | 99 | // lower right 100 | surface.DrawTexturedRect( wideHalf, tallHalf, texWide, texTall ); 101 | 102 | // lower left 103 | surface.DrawTexturedSubRect( x0, tallHalf, x0+texWide, tallHalf+texTall, 1., 0., 0., 1. ); 104 | 105 | // upper left 106 | surface.DrawTexturedSubRect( x0, 0, x0+texWide, texTall, 1., 1., 0., 0. ); 107 | 108 | // upper right 109 | surface.DrawTexturedSubRect( wideHalf, 0, wideHalf+texWide, texTall, 0., 1., 1., 0. ); 110 | 111 | // left 112 | surface.DrawFilledRect( 0, 0, x0, tall ); 113 | 114 | // right 115 | surface.DrawFilledRect( wideHalf + texWide, 0, x0, tall ); 116 | } 117 | 118 | function CCSHudScope::SetVisible( state ) 119 | { 120 | m_bVisible = state; 121 | return self.SetVisible( state ); 122 | } 123 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudsquadstatus.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface; 8 | 9 | class CSGOHudSquadStatus 10 | { 11 | self = null 12 | m_iSquadMembers = 0 13 | m_hFont = null 14 | m_hFontIcon = null 15 | m_iIconWidth = 0 16 | m_iIconHeight = 0 17 | m_bVisible = false 18 | } 19 | 20 | function CSGOHudSquadStatus::Init() 21 | { 22 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudSquadStatus" ) 23 | self.SetSize( XRES(640), YRES(480) ); 24 | self.SetVisible( m_bVisible ); 25 | self.SetPaintBackgroundEnabled( false ); 26 | self.SetCallback( "Paint", Paint.bindenv(this) ); 27 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 28 | 29 | m_hFont = surface.GetFont( "hud-HA-text-sm", true ); 30 | m_hFontIcon = surface.GetFont( "SquadIcon", true, "ClientScheme" ); 31 | if ( !m_hFontIcon ) 32 | { 33 | m_hFontIcon = surface.GetFont( "weapon-selection-item-icon", true ); 34 | } 35 | } 36 | 37 | function CSGOHudSquadStatus::PerformLayout() 38 | { 39 | m_iIconWidth = surface.GetCharacterWidth( m_hFontIcon, 'C' ); 40 | m_iIconHeight = surface.GetFontTall( m_hFontIcon ) / 3; 41 | } 42 | 43 | function CSGOHudSquadStatus::Paint() 44 | { 45 | local width = YRES(64); 46 | local height = YRES(22); 47 | 48 | local scrh = YRES(480); 49 | 50 | local x0 = XRES(394); 51 | local y0 = scrh - height; 52 | 53 | // bg 54 | { 55 | local flAlpha = CSHud.m_flBackgroundAlpha; 56 | 57 | local w = width / 4; 58 | surface.SetColor( 0x00, 0x00, 0x00, 0xcc * flAlpha ); 59 | surface.DrawFilledRectFade( x0, y0, w, height, 0x00, 0xff, true ); 60 | local x = x0 + w; 61 | surface.DrawFilledRect( x, y0, w + w, height ); 62 | surface.DrawFilledRectFade( x + w + w, y0, w, height, 0xff, 0x00, true ); 63 | } 64 | 65 | surface.SetTextFont( m_hFontIcon ); 66 | surface.SetTextColor( 0xe7, 0xe7, 0xe7, 0x99 ); 67 | 68 | local iconWidth = m_iIconWidth; 69 | local iconWidthHalf = iconWidth / 2; 70 | local y = y0 - m_iIconHeight; 71 | 72 | local c = m_iSquadMembers; 73 | if ( c < 6 ) 74 | { 75 | local spacing = iconWidth + YRES(2); 76 | local totalWidth = (c-1) * spacing; 77 | local x = x0 + ( width - totalWidth ) / 2 - iconWidthHalf; 78 | 79 | while ( c-- ) 80 | { 81 | surface.SetTextPos( x, y ); 82 | surface.DrawUnicodeChar( 'C', 0 ); 83 | x += spacing; 84 | } 85 | } 86 | else 87 | { 88 | local x = x0 + ( width ) / 2 - iconWidthHalf; 89 | 90 | surface.SetTextPos( x, y ); 91 | surface.DrawUnicodeChar( 'C', 0 ); 92 | 93 | surface.SetTextFont( m_hFont ); 94 | surface.SetTextColor( 0xcc, 0xcc, 0xcc, 0xff ); 95 | surface.SetTextPos( x + iconWidth, y0 + YRES(8.5) ); 96 | surface.DrawUnicodeChar( 'x', 0 ); 97 | surface.DrawText( ""+c, 0 ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /mapbase/cs_hud/hudsuit.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local CSHud = this; 6 | local XRES = XRES, YRES = YRES; 7 | local surface = surface; 8 | 9 | 10 | class CSGOHudFlashlight 11 | { 12 | self = null 13 | m_flFlashlight = 0.0 14 | 15 | m_bFading = false 16 | } 17 | 18 | function CSGOHudFlashlight::Init() 19 | { 20 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudFlashlight" ) 21 | self.SetSize( XRES(640), YRES(480) ); 22 | self.SetVisible( false ); 23 | self.SetPaintBackgroundEnabled( false ); 24 | self.SetCallback( "Paint", Paint.bindenv(this) ); 25 | 26 | m_flFlashlight = 1.0; 27 | 28 | m_bFading = true; 29 | } 30 | 31 | function CSGOHudFlashlight::FadeOut() 32 | { 33 | if ( m_bFading ) 34 | return; 35 | 36 | m_bFading = true; 37 | CSHud.PanelFadeOut( "CSGOHudFlashlight", self, 0.25 ); 38 | } 39 | 40 | function CSGOHudFlashlight::SetVisible() 41 | { 42 | self.SetAlpha( 255 ); 43 | self.SetVisible( true ); 44 | 45 | if ( m_bFading ) 46 | { 47 | m_bFading = false; 48 | CSHud.StopPanelFadeOut( "CSGOHudFlashlight" ); 49 | } 50 | } 51 | 52 | function CSGOHudFlashlight::Paint() 53 | { 54 | local width = YRES(20); 55 | local height = YRES(22); 56 | 57 | local x0 = YRES(286); 58 | local y0 = YRES(480) - height; 59 | 60 | // bg 61 | { 62 | local flAlpha = CSHud.m_flBackgroundAlpha; 63 | 64 | local w = width / 2; 65 | surface.SetColor( 0x00, 0x00, 0x00, 0xcc * flAlpha ); 66 | surface.DrawFilledRectFade( x0, y0, w, height, 0x00, 0xff, true ); 67 | local x = x0 + w; 68 | surface.DrawFilledRect( x, y0, w, height ); 69 | surface.DrawFilledRectFade( x + w, y0, w, height, 0xff, 0x00, true ); 70 | } 71 | 72 | // bar 73 | local bar_h = YRES(4.5); 74 | local bar_w = width; 75 | local bar_x = x0 + width / 4; 76 | local bar_y = y0 + YRES(10); 77 | 78 | surface.SetColor( 0x66, 0x66, 0x66, 0x99 ); 79 | surface.DrawFilledRect( bar_x, bar_y, bar_w, bar_h ); 80 | 81 | if ( m_flFlashlight > 0.25 ) 82 | { 83 | surface.SetColor( 0xe7, 0xe7, 0xe7, 0xff ); 84 | } 85 | else 86 | { 87 | surface.SetColor( 0xff, 0x00, 0x00, 0xff ); 88 | } 89 | 90 | surface.DrawFilledRect( bar_x, bar_y, bar_w * m_flFlashlight, bar_h ); 91 | 92 | // outline 93 | surface.SetColor( 0x88, 0x88, 0x88, 0x7f ); 94 | surface.DrawOutlinedRect( bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, 1 ); 95 | 96 | // icon 97 | //surface.SetTextFont( surface.GetFont( "weapon-selection-item-icon", true ) ); 98 | //surface.SetTextColor( 0xe7, 0xe7, 0xe7, 0xdd ); 99 | //surface.SetTextPos( x0 + YRES(3), y0 - YRES(15) ); 100 | //surface.DrawUnicodeChar( 174, 0 ); 101 | } 102 | 103 | 104 | //--------------------------------------------------------------------- 105 | //--------------------------------------------------------------------- 106 | 107 | 108 | class CSGOHudSuitPower 109 | { 110 | self = null 111 | m_flPower = 0.0 112 | 113 | m_bFading = false 114 | } 115 | 116 | function CSGOHudSuitPower::Init() 117 | { 118 | self = vgui.CreatePanel( "Panel", CSHud.GetRootPanel(), "CSGOHudSuitPower" ) 119 | self.SetSize( XRES(640), YRES(480) ); 120 | self.SetVisible( false ); 121 | self.SetPaintBackgroundEnabled( false ); 122 | self.SetCallback( "Paint", Paint.bindenv(this) ); 123 | 124 | m_flPower = 1.0; 125 | 126 | m_bFading = true; 127 | } 128 | 129 | function CSGOHudSuitPower::FadeOut() 130 | { 131 | if ( m_bFading ) 132 | return; 133 | 134 | m_bFading = true; 135 | CSHud.PanelFadeOut( "CSGOHudSuitPower", self, 0.25 ); 136 | } 137 | 138 | function CSGOHudSuitPower::SetVisible() 139 | { 140 | self.SetAlpha( 255 ); 141 | self.SetVisible( true ); 142 | 143 | if ( m_bFading ) 144 | { 145 | m_bFading = false; 146 | CSHud.StopPanelFadeOut( "CSGOHudSuitPower" ); 147 | } 148 | } 149 | 150 | function CSGOHudSuitPower::Paint() 151 | { 152 | local width = YRES(50); 153 | local height = YRES(22); 154 | 155 | local x0 = YRES(204); 156 | local y0 = YRES(480) - height; 157 | 158 | // bg 159 | { 160 | local flAlpha = CSHud.m_flBackgroundAlpha; 161 | 162 | local w = width / 2; 163 | surface.SetColor( 0x00, 0x00, 0x00, 0xcc * flAlpha ); 164 | surface.DrawFilledRectFade( x0, y0, w, height, 0x00, 0xff, true ); 165 | local x = x0 + w; 166 | surface.DrawFilledRect( x, y0, w, height ); 167 | surface.DrawFilledRectFade( x + w, y0, w, height, 0xff, 0x00, true ); 168 | } 169 | 170 | // bar 171 | local bar_h = YRES(4.5); 172 | local bar_w = width; 173 | local bar_x = x0 + width / 4; 174 | local bar_y = y0 + YRES(10); 175 | 176 | surface.SetColor( 0x66, 0x66, 0x66, 0x99 ); 177 | surface.DrawFilledRect( bar_x, bar_y, bar_w, bar_h ); 178 | 179 | if ( m_flPower > 0.25 ) 180 | { 181 | surface.SetColor( 0xe7, 0xe7, 0xe7, 0xff ); 182 | } 183 | else 184 | { 185 | surface.SetColor( 0xff, 0x00, 0x00, 0xff ); 186 | } 187 | 188 | surface.DrawFilledRect( bar_x, bar_y, bar_w * m_flPower, bar_h ); 189 | 190 | // outline 191 | surface.SetColor( 0x88, 0x88, 0x88, 0x7f ); 192 | surface.DrawOutlinedRect( bar_x - 1, bar_y - 1, bar_w + 2, bar_h + 2, 1 ); 193 | } 194 | -------------------------------------------------------------------------------- /mapbase/cs_hud/init.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // Counter-Strike: Global Offensive Panorama HUD 6 | // 7 | //------------------------------------------------------------- 8 | // Resource files: [csgo] 9 | // "resources/stratum2bold.ttf" 10 | // "sound/ui/weapon/zoom.wav" 11 | // "materials/overlays/scope_lens" 12 | // "materials/sprites/scope_arc" 13 | // "materials/panorama/images/icons/ui/health" (32x32) 14 | // "materials/panorama/images/icons/ui/shield" (32x32) 15 | // "materials/panorama/images/icons/ui/info" (32x32) 16 | // "materials/panorama/images/icons/ui/alert" (32x32) 17 | // "materials/panorama/images/masks/bottom-top-fade_additive" 18 | // "materials/panorama/images/hud/damageindicator/damage-segment_vert" 19 | // "materials/panorama/images/hud/damageindicator/damage-segment_horz" 20 | // "/damage-segment.png" 21 | // "materials/panorama/images/hud/reticle/crosshair" 22 | // "/crosshairpip2.png" 23 | // "/reticlecircle.png" 24 | // "materials/panorama/images/hud/reticle/reticlefriend_additive" 25 | //------------------------------------------------------------- 26 | 27 | const CSGOHUD_VERSION = 23120820; 28 | 29 | // Automatically detect the subdirectory. 30 | // Does not work if it was loaded with DoIncludeScript() 31 | local CSGOHUD_PATH = "cs_hud/"; 32 | local si = getstackinfos(3); 33 | if ( si ) 34 | { 35 | foreach ( k, v in si.locals ) 36 | { 37 | local i; 38 | if ( ( typeof v == "string" ) && ( ( i = v.find("init") ) != null ) ) 39 | { 40 | CSGOHUD_PATH = v.slice( 0, i ); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | const FLT_MAX = 3.402823466e+38; 47 | const PI = 3.141592654; 48 | 49 | local CONST = getconsttable(); 50 | CONST.CSGOHUD_PATH <- CSGOHUD_PATH; 51 | 52 | if ( !( "vec3_invalid" in CONST ) ) 53 | { 54 | CONST.vec3_invalid <- Vector( FLT_MAX, FLT_MAX, FLT_MAX ); 55 | } 56 | 57 | if ( !( "CSGOHUD_DMG_BITS" in CONST ) ) 58 | { 59 | const HIDEHUD_WEAPONSELECTION = 1; // Hide ammo count & weapon selection 60 | const HIDEHUD_FLASHLIGHT = 2; 61 | const HIDEHUD_ALL = 4; 62 | const HIDEHUD_HEALTH = 8; // Hide health & armor / suit battery 63 | const HIDEHUD_PLAYERDEAD = 16; // Hide when local player's dead 64 | const HIDEHUD_NEEDSUIT = 32; // Hide when the local player doesn't have the HEV suit 65 | const HIDEHUD_MISCSTATUS = 64; // Hide miscellaneous status elements (trains, pickup history, death notices, etc) 66 | const HIDEHUD_CHAT = 128; // Hide all communication elements (saytext, voice icon, etc) 67 | const HIDEHUD_CROSSHAIR = 256; // Hide crosshairs 68 | const HIDEHUD_VEHICLE_CROSSHAIR = 512; // Hide vehicle crosshair 69 | const HIDEHUD_INVEHICLE = 1024; 70 | const HIDEHUD_BONUS_PROGRESS = 2048; 71 | 72 | CONST.CSGOHUD_HIDEHUD_CROSSHAIR <- ( HIDEHUD_ALL | HIDEHUD_PLAYERDEAD | HIDEHUD_CROSSHAIR | HIDEHUD_VEHICLE_CROSSHAIR ); 73 | CONST.CSGOHUD_HIDEHUD_AMMO <- ( HIDEHUD_ALL | HIDEHUD_PLAYERDEAD | HIDEHUD_HEALTH | HIDEHUD_WEAPONSELECTION | HIDEHUD_NEEDSUIT ); 74 | CONST.CSGOHUD_HIDEHUD_WEPSELECTION <- ( HIDEHUD_ALL | HIDEHUD_PLAYERDEAD | HIDEHUD_WEAPONSELECTION | HIDEHUD_NEEDSUIT | HIDEHUD_INVEHICLE ); 75 | CONST.CSGOHUD_HIDEHUD_HEALTH <- ( HIDEHUD_ALL | HIDEHUD_PLAYERDEAD | HIDEHUD_HEALTH | HIDEHUD_NEEDSUIT ); 76 | 77 | CONST.CSGOHUD_DMG_BITS <- ( DMG_CLUB | DMG_BULLET | DMG_BLAST | DMG_POISON | DMG_ACID | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK | DMG_SLASH ); 78 | CONST.CSGOHUD_DMG_NO_ORIGIN <- ( DMG_POISON | DMG_ACID | DMG_DROWN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION ); 79 | CONST.CSGOHUD_DMG_SCR_FX <- ( DMG_POISON | DMG_BURN | DMG_RADIATION ); 80 | 81 | CONST.PROP_DRIVABLE_APC_CLASSNAME <- IsWindows() ? "class C_PropDrivableAPC" : "17C_PropDrivableAPC"; 82 | CONST.PROP_AIRBOAT_CLASSNAME <- IsWindows() ? "class C_PropAirboat" : "13C_PropAirboat"; 83 | } 84 | 85 | local Init = function(...) 86 | { 87 | if ( CLIENT_DLL ) 88 | IncludeScript( CSGOHUD_PATH + "fonts.nut" ); 89 | 90 | if ( !("CSHud" in this) ) // Level transition (OnRestore) 91 | IncludeScript( CSGOHUD_PATH + "hud_cs.nut" ); 92 | 93 | if ( SERVER_DLL ) 94 | { 95 | CSHud.Init( vargv[0] ); 96 | } 97 | else // CLIENT_DLL 98 | { 99 | NetMsg.Receive( "CSGOHud.Load", null ); 100 | CSHud.Init(); 101 | } 102 | } 103 | 104 | ListenToGameEvent( "player_spawn", function( event ) 105 | { 106 | if ( SERVER_DLL ) 107 | { 108 | Init( GetPlayerByUserID( event.userid ) ); 109 | } 110 | else // CLIENT_DLL 111 | { 112 | Init(); 113 | Entities.First().SetContextThink( "CSGOHud", function(_) { StopListeningToAllGameEvents( "CSGOHud" ); }, 0.01 ); 114 | } 115 | }, "CSGOHud" ); 116 | 117 | // Save/restore 118 | { 119 | local InitRestore = function(...) 120 | { 121 | if ( SERVER_DLL ) 122 | { 123 | Init( Entities.GetLocalPlayer() ); 124 | } 125 | else // CLIENT_DLL 126 | { 127 | // Level transition hack 128 | Entities.First().SetContextThink( "CSGOHud", Init, 0.0 ); 129 | } 130 | } 131 | 132 | Hooks.Add( this, "OnRestore", InitRestore, "CSGOHud" ); 133 | 134 | // Handle loads on saves that were not saved with this HUD 135 | if ( SERVER_DLL ) 136 | { 137 | local t = GetLoadType(); 138 | if ( t == MapLoad.LoadGame || t == MapLoad.Transition ) 139 | { 140 | Entities.First().SetContextThink( "CSGOHud.Load", function(_) 141 | { 142 | // This is not well tested 143 | if ( "CSHud" in getroottable() ) 144 | { 145 | local reload = 0; 146 | 147 | if ( "version" in CSHud ) 148 | { 149 | // Save is more recent, don't reload 150 | if ( CSHud.version >= CSGOHUD_VERSION ) 151 | return; 152 | 153 | reload = 1; 154 | } 155 | else 156 | { 157 | if ( "StatusUpdate2" in CSHud ) // StatusUpdate2 was added in the same update as cs_hud_reload 158 | { 159 | reload = 1; 160 | } 161 | else 162 | { 163 | // Do nothing, the added complexity to reload this version is not worth it. 164 | print( "This save file includes an ancient version of CSGOHud. Not updating.\n" ); 165 | return; 166 | } 167 | } 168 | 169 | if ( reload ) 170 | { 171 | if ( "version" in CSHud ) 172 | { 173 | printf( "Updating CSGOHud to %i (from %i)\n", CSGOHUD_VERSION, CSHud.version ); 174 | } 175 | else 176 | { 177 | printf( "Updating CSGOHud to %i\n", CSGOHUD_VERSION ); 178 | } 179 | 180 | // Wait for player to spawn 181 | Entities.First().SetContextThink( "CSGOHud.Load2", function(_) 182 | { 183 | SendToConsole( "cs_hud_reload" ); 184 | }, 0.25 ); 185 | } 186 | 187 | // Let client handle the reload 188 | return; 189 | } 190 | else 191 | { 192 | print( "This save file does not include CSGOHud, loading...\n" ); 193 | } 194 | 195 | Hooks.Add( this, "OnRestore", InitRestore, "CSGOHud" ); 196 | 197 | local player = Entities.GetLocalPlayer(); 198 | Init( player ); 199 | NetMsg.Start( "CSGOHud.Load" ); 200 | NetMsg.Send( player, true ); 201 | }, 0.1 ); 202 | } 203 | } 204 | else // CLIENT_DLL 205 | { 206 | // Hooks are reset on save restore because hook functions are stored in the VM. 207 | // NetMsg functions are not reset because they are stored in C++. 208 | // Hence the need to re-register the hook but not the net messages. 209 | NetMsg.Receive( "CSGOHud.Load", function() 210 | { 211 | Hooks.Add( this, "OnRestore", InitRestore, "CSGOHud" ); 212 | Init(); 213 | } ); 214 | } 215 | } 216 | 217 | if ( !("GetPlayerByUserID" in this) ) 218 | { 219 | function GetPlayerByUserID(i) 220 | { 221 | for ( local p; p = Entities.FindByClassname( p, "player" ); ) 222 | if ( p.GetUserID() == i ) 223 | return p; 224 | } 225 | } 226 | 227 | CSGOHud_Init <- Init; 228 | -------------------------------------------------------------------------------- /mapbase/hud_override.nut: -------------------------------------------------------------------------------- 1 | // 2 | // Hud visibility manager 3 | // 4 | // SetHUDHiddenBits( i ) 5 | // ClearHUDHiddenBits( i ) 6 | // GetHUDHiddenBits() 7 | // 8 | 9 | const HIDEHUD_WEAPONSELECTION = 1 // Hide ammo count & weapon selection 10 | const HIDEHUD_FLASHLIGHT = 2 11 | const HIDEHUD_ALL = 4 12 | const HIDEHUD_HEALTH = 8 // Hide health & armor / suit battery 13 | const HIDEHUD_PLAYERDEAD = 16 // Hide when local player's dead 14 | const HIDEHUD_NEEDSUIT = 32 // Hide when the local player doesn't have the HEV suit 15 | const HIDEHUD_MISCSTATUS = 64 // Hide miscellaneous status elements (trains, pickup history, death notices, etc) 16 | const HIDEHUD_CHAT = 128 // Hide all communication elements (saytext, voice icon, etc) 17 | const HIDEHUD_CROSSHAIR = 256 // Hide crosshairs 18 | const HIDEHUD_VEHICLE_CROSSHAIR = 512 // Hide vehicle crosshair 19 | const HIDEHUD_INVEHICLE = 1024 20 | const HIDEHUD_BONUS_PROGRESS = 2048 21 | 22 | if ( CLIENT_DLL ) 23 | { 24 | local Convars = Convars; 25 | local m_iHideHud = 0; 26 | 27 | function SetHUDHiddenBits( i ) 28 | { 29 | return Convars.SetInt( "hidehud", m_iHideHud = m_iHideHud | i ); 30 | } 31 | 32 | function ClearHUDHiddenBits( i ) 33 | { 34 | return Convars.SetInt( "hidehud", m_iHideHud = m_iHideHud & (~i) ); 35 | } 36 | 37 | function GetHUDHiddenBits() 38 | { 39 | return m_iHideHud; 40 | } 41 | 42 | local Init = function(...) 43 | { 44 | Hooks.Add( Entities.GetLocalPlayer().GetOrCreatePrivateScriptScope(), 45 | "UpdateOnRemove", 46 | function() { return ClearHUDHiddenBits(-1) }, 47 | "hud_override" ); 48 | } 49 | ListenToGameEvent( "player_spawn", Init, "hud_override" ); 50 | Hooks.Add( this, "OnRestore", Init, "hud_override" ); 51 | } 52 | -------------------------------------------------------------------------------- /mapbase/keylistener.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // Register callbacks for any key at all. 6 | // 7 | // server: 8 | // SetKeyListener( CBasePlayer player, string keyName, closure fnPressed, closure fnReleased = null ) 9 | // 10 | // client: 11 | // SetKeyListener( string keyName, closure fnPressed, closure fnReleased = null ) 12 | // KeyListener_SendInput( bool state, enum ButtonCode button ) 13 | // 14 | // 15 | 16 | 17 | local NetMsg = NetMsg; 18 | 19 | local g_OnPressed = {} 20 | local g_OnReleased = {} 21 | 22 | local Init; 23 | 24 | if ( SERVER_DLL ) 25 | { 26 | local g_KeyLookup = {} 27 | local bQ = true; 28 | 29 | local ClientRegister = function(...) 30 | { 31 | local c = g_KeyLookup.len(); 32 | if ( c ) 33 | { 34 | NetMsg.Start( "KeyListener.Reg" ); 35 | NetMsg.WriteByte( c ); 36 | foreach( k, v in g_KeyLookup ) 37 | { 38 | NetMsg.WriteString( k ); 39 | NetMsg.WriteBool( v[0] != null ); 40 | NetMsg.WriteBool( v[1] != null ); 41 | } 42 | NetMsg.Send( player, true ); 43 | } 44 | } 45 | 46 | function SetKeyListener( player, keyName, fnPressed, fnReleased = null ) 47 | { 48 | g_KeyLookup[ keyName.toupper() ] <- [ fnPressed, fnReleased ]; 49 | 50 | if ( bQ ) 51 | { 52 | bQ = false; 53 | Entities.First().SetContextThink( "KeyListener.Reg", ClientRegister, IntervalPerTick()+0.001 ); 54 | } 55 | } 56 | 57 | Init = function(...) 58 | { 59 | NetMsg.Receive( "KeyListener.Reg", function( player ) 60 | { 61 | bQ = true; 62 | 63 | local c = NetMsg.ReadByte(); 64 | while ( c-- ) 65 | { 66 | local button = NetMsg.ReadByte(); 67 | local key = NetMsg.ReadString().toupper(); 68 | if ( key in g_KeyLookup ) 69 | { 70 | local callbacks = delete g_KeyLookup[ key ]; 71 | 72 | g_OnPressed[ button ] <- callbacks[0]; 73 | g_OnReleased[ button ] <- callbacks[1]; 74 | 75 | printf( "KeyListener.Register: %s[%d]\n", key, button ); 76 | } 77 | } 78 | } ); 79 | 80 | NetMsg.Receive( "KeyListener.InputDown", function( player ) 81 | { 82 | return g_OnPressed[ NetMsg.ReadByte() ](); 83 | } ); 84 | 85 | NetMsg.Receive( "KeyListener.InputRelease", function( player ) 86 | { 87 | return g_OnReleased[ NetMsg.ReadByte() ](); 88 | } ); 89 | 90 | return Entities.First().SetContextThink( "KeyListener_", function(_) 91 | { 92 | return StopListeningToAllGameEvents( "KeyListener" ); 93 | }, 0.1 ); 94 | } 95 | } 96 | 97 | if ( CLIENT_DLL ) 98 | { 99 | local input = input; 100 | 101 | local g_KeyState = {} 102 | local g_ReleasedSV = {} 103 | local g_PressedSV = {} 104 | 105 | function KeyListener_SendInput( state, button ) 106 | { 107 | if ( state ) 108 | { 109 | if ( button in g_OnPressed ) 110 | g_OnPressed[ button ](); 111 | 112 | if ( button in g_PressedSV ) 113 | { 114 | NetMsg.Start( "KeyListener.InputDown" ); 115 | NetMsg.WriteByte( button ); 116 | return NetMsg.Send(); 117 | } 118 | } 119 | else 120 | { 121 | if ( button in g_OnReleased ) 122 | g_OnReleased[ button ](); 123 | 124 | if ( button in g_ReleasedSV ) 125 | { 126 | NetMsg.Start( "KeyListener.InputRelease" ); 127 | NetMsg.WriteByte( button ); 128 | return NetMsg.Send(); 129 | } 130 | } 131 | } 132 | 133 | function SetKeyListener( keyName, fnPressed, fnReleased = null ) 134 | { 135 | local button = input.StringToButtonCode( keyName ); 136 | if ( button <= 0 ) 137 | return Warning( "SetKeyListener: Invalid key name '"+keyName+"'\n" ); 138 | 139 | g_KeyState[ button ] <- false; 140 | 141 | if ( fnPressed ) 142 | { 143 | g_OnPressed[ button ] <- fnPressed; 144 | } 145 | else if ( button in g_OnPressed ) 146 | { 147 | delete g_OnPressed[button]; 148 | } 149 | 150 | if ( fnReleased ) 151 | { 152 | g_OnReleased[ button ] <- fnReleased; 153 | } 154 | else if ( button in g_OnPressed ) 155 | { 156 | delete g_OnPressed[button]; 157 | } 158 | 159 | local bind = input.BindingForKey( button ); 160 | if ( bind ) 161 | printf( "KeyListener.Register: %s[%d] (bind '%s')\n", keyName, button, bind ); 162 | else 163 | printf( "KeyListener.Register: %s[%d]\n", keyName, button ); 164 | } 165 | 166 | local KeyListenerThink = function(_) 167 | { 168 | foreach ( button, bWasDown in g_KeyState ) 169 | { 170 | if ( input.IsButtonDown( button ) ) 171 | { 172 | if ( !bWasDown ) 173 | { 174 | g_KeyState[ button ] = true; 175 | 176 | if ( button in g_PressedSV ) 177 | { 178 | NetMsg.Start( "KeyListener.InputDown" ); 179 | NetMsg.WriteByte( button ); 180 | NetMsg.Send(); 181 | } 182 | 183 | if ( button in g_OnPressed ) 184 | { 185 | g_OnPressed[ button ](); 186 | } 187 | } 188 | } 189 | else if ( bWasDown ) 190 | { 191 | g_KeyState[ button ] = false; 192 | 193 | if ( button in g_ReleasedSV ) 194 | { 195 | NetMsg.Start( "KeyListener.InputRelease" ); 196 | NetMsg.WriteByte( button ); 197 | NetMsg.Send(); 198 | } 199 | 200 | if ( button in g_OnReleased ) 201 | { 202 | g_OnReleased[ button ](); 203 | } 204 | } 205 | } 206 | return 0.0; 207 | } 208 | 209 | Init = function(...) 210 | { 211 | NetMsg.Receive( "KeyListener.Reg", function() 212 | { 213 | local c = NetMsg.ReadByte(); 214 | local i = c; 215 | NetMsg.Start( "KeyListener.Reg" ); 216 | NetMsg.WriteByte( c ); 217 | while ( i-- ) 218 | { 219 | local key = NetMsg.ReadString(); 220 | local button = input.StringToButtonCode( key ); 221 | if ( button <= 0 ) 222 | Warning( "Invalid key name '"+key+"'\n" ); 223 | 224 | g_KeyState[ button ] <- false; 225 | 226 | if ( NetMsg.ReadBool() ) 227 | g_PressedSV[ button ] <- true; 228 | 229 | if ( NetMsg.ReadBool() ) 230 | g_ReleasedSV[ button ] <- true; 231 | 232 | NetMsg.WriteByte( button ); 233 | NetMsg.WriteString( key ); 234 | 235 | local bind = input.BindingForKey( button ); 236 | if ( bind ) 237 | printf( "KeyListener.Register: %s[%d] (bind '%s')\n", key, button, bind ); 238 | else 239 | printf( "KeyListener.Register: %s[%d]\n", key, button ); 240 | } 241 | NetMsg.Send(); 242 | } ); 243 | 244 | Entities.First().SetContextThink( "KeyListener", KeyListenerThink, 0.1 ); 245 | 246 | return Entities.First().SetContextThink( "KeyListener_", function(_) 247 | { 248 | return StopListeningToAllGameEvents( "KeyListener" ); 249 | }, 0.1 ); 250 | } 251 | } 252 | 253 | ListenToGameEvent( "player_spawn", Init, "KeyListener" ); 254 | Hooks.Add( this, "OnRestore", Init, "KeyListener" ); 255 | 256 | KeyListener_Init <- Init; 257 | -------------------------------------------------------------------------------- /mapbase/readme.md: -------------------------------------------------------------------------------- 1 | 2 | Achievements example: 3 | https://gist.github.com/samisalreadytaken/1d9a101aeae4635009a6bcd0c29060ba 4 | 5 | Steam friend notifications example: 6 | https://gist.github.com/samisalreadytaken/aa1fc9f3160db361bece11a940ceaa0b 7 | -------------------------------------------------------------------------------- /mapbase/steam/AchievementNotification.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | //------------------- Copyright (c) samisalreadytaken ------------------- 3 | // github.com/samisalreadytaken 4 | //----------------------------------------------------------------------- 5 | // 6 | // client: 7 | // CreateAchievementNotification_Unlocked( string description, string image ) 8 | // CreateAchievementNotification_Progress( int cur, int max, string description, string image ) 9 | // 10 | // 11 | 12 | if ( SERVER_DLL ) 13 | return; 14 | 15 | local Fmt = format; 16 | 17 | function CreateAchievementNotification_Unlocked( description, image ) 18 | { 19 | CSteamAchievementNotification( 20 | "#Friends_AchievementUnlocked_Headline", 21 | description, 22 | image ); 23 | } 24 | 25 | function CreateAchievementNotification_Progress( cur, max, description, image ) 26 | { 27 | CSteamAchievementNotification( 28 | "#Friends_AchievementProgress_Headline", 29 | Fmt( "%s (%s/%s)", description, prettifynum(cur), prettifynum(max) ), 30 | image ); 31 | } 32 | 33 | //-------------------------------------------------------------- 34 | //-------------------------------------------------------------- 35 | 36 | local GetLocalisation = function( txt ) 37 | { 38 | txt = Localize.GetTokenAsUTF8( txt ); 39 | if ( txt[0] != '#' ) 40 | return txt; 41 | 42 | switch ( txt ) 43 | { 44 | case "#Friends_AchievementUnlocked_Headline": 45 | txt = "Achievement Unlocked!"; 46 | break; 47 | 48 | case "#Friends_AchievementProgress_Headline": 49 | txt = "Achievement Progress"; 50 | break; 51 | } 52 | return txt; 53 | } 54 | 55 | 56 | class CSteamAchievementNotification extends SteamNotificationManager.CBaseNotification 57 | { 58 | m_DarkenedRegion = null 59 | m_AchievementIcon = null 60 | m_LabelTitle = null 61 | m_LabelDescription = null 62 | } 63 | 64 | function CSteamAchievementNotification::constructor( title, description, image ) 65 | { 66 | base.constructor( "AchievementNotification" ); 67 | 68 | m_DarkenedRegion = vgui.CreatePanel( "Panel", self, "DarkenedRegion" ); 69 | m_DarkenedRegion.MakeReadyForUse(); 70 | m_DarkenedRegion.SetZPos( -1 ); 71 | m_DarkenedRegion.SetVisible( true ); 72 | m_DarkenedRegion.SetPaintEnabled( false ); 73 | m_DarkenedRegion.SetPaintBackgroundEnabled( true ); 74 | 75 | m_AchievementIcon = vgui.CreatePanel( "ImagePanel", self, "AchievementIcon" ); 76 | m_AchievementIcon.MakeReadyForUse(); 77 | m_AchievementIcon.SetVisible( true ); 78 | m_AchievementIcon.SetShouldScaleImage( false ); 79 | m_AchievementIcon.SetImage( image, false ); 80 | 81 | //m_IconBorder = vgui.CreatePanel( "ImagePanel", self, "IconBorder" ); 82 | //m_IconBorder.MakeReadyForUse(); 83 | //m_IconBorder.SetZPos( 1 ); 84 | //m_IconBorder.SetVisible( true ); 85 | //m_IconBorder.SetShouldScaleImage( true ); 86 | //m_IconBorder.SetImage( "steam/graphics/achievementbg", false ); 87 | 88 | if ( title[0] == '#' ) 89 | title = GetLocalisation( title ); 90 | 91 | if ( description[0] == '#' ) 92 | description = GetLocalisation( description ); 93 | 94 | m_LabelTitle = vgui.CreatePanel( "Label", self, "LabelTitle" ); 95 | m_LabelTitle.MakeReadyForUse(); 96 | m_LabelTitle.SetVisible( true ); 97 | m_LabelTitle.SetPaintBackgroundEnabled( false ); 98 | m_LabelTitle.SetContentAlignment( Alignment.northwest ); 99 | m_LabelTitle.SetFont( surface.GetFont( "SteamScheme.FriendsSmall", false ) ); 100 | m_LabelTitle.SetWrap( true ); 101 | m_LabelTitle.SetText( title ); 102 | 103 | m_LabelDescription = vgui.CreatePanel( "Label", self, "LabelDescription" ); 104 | m_LabelDescription.MakeReadyForUse(); 105 | m_LabelDescription.SetVisible( true ); 106 | m_LabelDescription.SetPaintBackgroundEnabled( false ); 107 | m_LabelDescription.SetContentAlignment( Alignment.northwest ); 108 | m_LabelDescription.SetFont( surface.GetFont( "SteamScheme.FriendsSmall", false ) ); 109 | m_LabelDescription.SetWrap( true ); 110 | m_LabelDescription.SetText( description ); 111 | 112 | PerformLayout(); 113 | } 114 | 115 | function CSteamAchievementNotification::PerformLayout() 116 | { 117 | // "friends/AchievementNotification.res" 118 | base.PerformLayout( 240, 94 ); 119 | 120 | m_DarkenedRegion.SetPos( 1, 74 ); 121 | m_DarkenedRegion.SetSize( 238, 23 ); 122 | local clr = SteamScheme["ClientBG"]; 123 | m_DarkenedRegion.SetBgColor( clr[0], clr[1], clr[2], clr[3] ); 124 | 125 | m_AchievementIcon.SetPos( 14, 14 ); 126 | m_AchievementIcon.SetSize( 64, 64 ); 127 | 128 | //m_IconBorder.SetPos( 13, 13 ); 129 | //m_IconBorder.SetSize( 66, 66 ); 130 | 131 | m_LabelTitle.SetPos( 88, 25 ); 132 | m_LabelTitle.SetSize( 144, 28 ); 133 | clr = SteamScheme["AchievementPopup.TitleColor"]; 134 | m_LabelTitle.SetFgColor( clr[0], clr[1], clr[2], clr[3] ); 135 | 136 | m_LabelDescription.SetPos( 88, 53 ); 137 | m_LabelDescription.SetSize( 144, 28 ); 138 | clr = SteamScheme["AchievementPopup.DescriptionColor"]; 139 | m_LabelDescription.SetFgColor( clr[0], clr[1], clr[2], clr[3] ); 140 | } 141 | -------------------------------------------------------------------------------- /mapbase/steam/fonts.nut: -------------------------------------------------------------------------------- 1 | 2 | surface.CreateFont( "SteamScheme.FriendsSmall", 3 | { 4 | "name" : "Arial" 5 | "tall" : 14 6 | "weight" : 400 7 | "antialias" : true 8 | "proportional" : false 9 | } ); 10 | -------------------------------------------------------------------------------- /mapbase/steam/init.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // SteamAchievements ------------------------------------------ 6 | // 7 | // "SteamAchievementsPostInit" hook is called post init. 8 | // 9 | // server: 10 | // SteamAchievements::LoadFromFile( string fileName ) 11 | // SteamAchievements::SetAchievement( player, string ID ) 12 | // SteamAchievements::SetStat( player, string ID, int progress ) 13 | // SteamAchievements::IncrementStat( player, string ID, int amount ) 14 | // SteamAchievements::IndicateAchievementProgress( player, string ID ) 15 | // SteamAchievements::GetAchievement( player, string ID ) 16 | // SteamAchievements::GetStat( player, string ID ) 17 | // SteamAchievements::GetAchievementUnlockTime( player, string ID ) // unix time, 0 if not unlocked 18 | // SteamAchievements::GetAchievementUnlockDateString( player, string ID, bool bLocalTime, bool bISO8601 ) 19 | // SteamAchievements::StoreStats( player ) // write to permanent storage, automatically called on player disconnect 20 | // SteamAchievements::ClearAchievement( player, string ID ) 21 | // 22 | // client: 23 | // SteamAchievements::LoadFromFile( string fileName ) 24 | // SteamAchievements::RequestCurrentStats() 25 | // SteamAchievements::GetAchievement( string ID ) 26 | // SteamAchievements::GetStat( string ID ) 27 | // SteamAchievements::GetAchievementUnlockTime( string ID ) 28 | // SteamAchievements::GetAchievementUnlockDateString( string ID, bool bLocalTime, bool bISO8601 ) 29 | // 30 | // 31 | // if 'AchievementDisplay.nut' is included, use 'display_achievements' console command to view all loaded achievements. 32 | // 33 | // 34 | // AchievementNotification ------------------------------------ 35 | // 36 | // client: 37 | // CreateAchievementNotification_Unlocked( string description, string image ) 38 | // CreateAchievementNotification_Progress( int cur, int max, string description, string image ) 39 | // 40 | // 41 | // 42 | // FriendNotification ----------------------------------------- 43 | // 44 | // szImage can also take Steam2ID string "STEAM_0:0:0" 45 | // 46 | // server: 47 | // SendSteamFriendNotification_Online( CBasePlayer player, string szImage, string szSender ) 48 | // SendSteamFriendNotification_InGame( CBasePlayer player, string szImage, string szSender, string szGame ) 49 | // SendSteamFriendNotification_InApp( CBasePlayer player, string szImage, string szSender, string szGame ) 50 | // SendSteamFriendNotification_ChatMsg( CBasePlayer player, string szImage, string szSender, enum PersonaState nSenderState, string szMsg ) 51 | // SendSteamFriendNotification_GameInvite( CBasePlayer player, string szImage, string szSender, string szGame ) 52 | // SendSteamFriendNotification_FriendInvitation( CBasePlayer player, string szImage, string szSender ) 53 | // 54 | // client: 55 | // CreateSteamFriendNotification_Online( string szImage, string szSender ) 56 | // CreateSteamFriendNotification_InGame( string szImage, string szSender, string szGame ) 57 | // CreateSteamFriendNotification_InApp( string szImage, string szSender, string szGame ) 58 | // CreateSteamFriendNotification_ChatMsg( enum PersonaState nSenderState, string szImage, string szSender, string szMsg ) 59 | // CreateSteamFriendNotification_GameInvite( string szImage, string szSender, string szGame ) 60 | // CreateSteamFriendNotification_FriendInvitation( string szImage, string szSender ) 61 | // 62 | // 63 | // 64 | // NotificationManager ---------------------------------------- 65 | // 66 | // server: 67 | // SetSteamNotificationPosition( player, enum SteamNotificationPosition ) 68 | // 69 | // client: 70 | // SetSteamNotificationPosition( enum SteamNotificationPosition ) 71 | // 72 | //------------------------------------------------------------- 73 | // Resource files: [steam] 74 | // Avatar border images are resized to 64x64 from 40x40 without scaling 75 | // "sound/steam/friends/message.wav" 76 | // "materials/steam/graphics/avatar_32blank" 77 | // "materials/steam/graphics/avatarBorderInGame" 78 | // "materials/steam/graphics/avatarBorderOffline" 79 | // "materials/steam/graphics/avatarBorderOnline" 80 | //------------------------------------------------------------- 81 | 82 | 83 | enum SteamNotificationPosition 84 | { 85 | TopLeft, TopRight, BottomLeft, BottomRight 86 | } 87 | 88 | enum SteamFriendNotification 89 | { 90 | Online, 91 | InGame, 92 | InApp, 93 | ChatMsg, 94 | GameInvite, 95 | FriendInvitation 96 | } 97 | 98 | enum PersonaState 99 | { 100 | Offline, 101 | Online, 102 | InGame 103 | } 104 | 105 | // Automatically detect the subdirectory. 106 | // Does not work if it was loaded with DoIncludeScript() 107 | local _PATH = "steam/"; 108 | local si = getstackinfos(3); 109 | if ( si ) 110 | { 111 | foreach ( k, v in si.locals ) 112 | { 113 | local i; 114 | if ( ( typeof v == "string" ) && ( ( i = v.find("init") ) != null ) ) 115 | { 116 | _PATH = v.slice( 0, i ); 117 | break; 118 | } 119 | } 120 | } 121 | 122 | local Init = function(...) 123 | { 124 | if ( CLIENT_DLL ) 125 | IncludeScript( _PATH + "fonts.nut" ); 126 | 127 | if ( !("SteamNotificationManager" in this) ) // Level transition (OnRestore) 128 | { 129 | IncludeScript( _PATH + "utils.nut" ); 130 | IncludeScript( _PATH + "NotificationManager.nut" ); 131 | IncludeScript( _PATH + "FriendNotification.nut" ); 132 | IncludeScript( _PATH + "AchievementNotification.nut" ); 133 | 134 | if ( CLIENT_DLL ) 135 | IncludeScript( _PATH + "AchievementDisplay.nut" ); 136 | } 137 | 138 | // always redefine classes. saverestore bug. see mapbase-source#221 139 | IncludeScript( _PATH + "AchievementManager.nut" ); 140 | 141 | SteamAchievements.Init(); 142 | 143 | if ( CLIENT_DLL ) 144 | SteamNotificationManager.Init(); 145 | 146 | if ( CLIENT_DLL ) 147 | SteamAchievementsDisplay.Init(); 148 | 149 | Hooks.Call( "SteamAchievementsPostInit", null ); 150 | } 151 | 152 | local InitRestore = function(...) 153 | { 154 | if ( SERVER_DLL ) 155 | { 156 | Init(); 157 | } 158 | 159 | if ( CLIENT_DLL ) 160 | { 161 | // Level transition hack 162 | Entities.First().SetContextThink( "SteamUtils", Init, 0.0 ); 163 | } 164 | } 165 | 166 | ListenToGameEvent( "player_spawn", function( event ) 167 | { 168 | // server: entities have spawned, collect and setup logic_achievements 169 | // client: local player spawned, tell the server 170 | // TODO: uncomment for multiplayer 171 | // if ( SERVER_DLL || GetPlayerByUserID( event.userid ) == Entities.GetLocalPlayer() ) 172 | { 173 | Init(); 174 | Entities.First().SetContextThink( "SteamUtils", function(_) { StopListeningToAllGameEvents( "SteamUtils" ); }, 0.0 ); 175 | } 176 | }, "SteamUtils" ); 177 | 178 | Hooks.Add( this, "OnRestore", InitRestore, "SteamUtils" ); 179 | -------------------------------------------------------------------------------- /mapbase/steam/utils.nut: -------------------------------------------------------------------------------- 1 | 2 | local Fmt = format; 3 | ::prettifynum <- function( val ) 4 | { 5 | local out = ""; 6 | local div = 1; 7 | 8 | if ( val < 0 ) 9 | { 10 | out += "-"; 11 | val = -val; 12 | } 13 | 14 | for ( local i = 6; i--; ) 15 | { 16 | if ( val < div * 1000 ) 17 | break; 18 | div *= 1000; 19 | } 20 | 21 | local prt = val / div; 22 | out += prt; 23 | 24 | for (;;) 25 | { 26 | val -= prt * div; 27 | div /= 1000; 28 | if ( !div ) 29 | break; 30 | prt = val / div; 31 | out += Fmt( ",%03d", prt ); 32 | } 33 | 34 | return out; 35 | } 36 | 37 | ::_hashstr <- function( s ) 38 | { 39 | local l = s.len(), h = l, t = (l >> 5) | 1, i = 0; 40 | for ( ; l >= t; l -= t ) 41 | h = h ^ ( (h<<5)+(h>>2)+s[i++] ); 42 | return h; 43 | } 44 | 45 | if ( CLIENT_DLL ) 46 | { 47 | SteamScheme <- 48 | { 49 | "Highlight5" : [ 24 53 82 255 ] 50 | 51 | "ClientBG" : [ 18 26 42 255 ] 52 | "DialogBG" : [ 42 46 51 255 ] 53 | 54 | "Label" : [ 168 172 179 255 ] 55 | "Label2" : [ 107 112 123 255 ] 56 | 57 | "Friends.InGameColor" : [ 144 186 60 255 ] 58 | "Friends.OnlineColor" : [ 84 165 196 255 ] 59 | "Friends.OfflineColor" : [ 127 127 127 255 ] 60 | 61 | "AchievementPopup.TitleColor" : [ 200 208 220 255 ] 62 | "AchievementPopup.DescriptionColor" : [ 180 180 180 255 ] 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /mapbase/tf_hud/fonts.nut: -------------------------------------------------------------------------------- 1 | 2 | surface.CreateFont( "HudFontGiantBold", 3 | { 4 | "name" : "TF2 Build" 5 | "tall" : 44 6 | "weight" : 500 7 | "additive" : false 8 | "antialias" : true 9 | "proportional" : true 10 | } ); 11 | 12 | surface.CreateFont( "HudFontMediumSmall", 13 | { 14 | "name" : "TF2" 15 | "tall" : 18 16 | "weight" : 500 17 | "additive" : false 18 | "antialias" : true 19 | "proportional" : true 20 | } ); 21 | 22 | surface.CreateFont( "TFFontSmall", 23 | { 24 | "name" : "Verdana" 25 | "tall" : 8 26 | "weight" : 0 27 | "additive" : true 28 | "antialias" : true 29 | "proportional" : true 30 | } ); 31 | 32 | surface.CreateFont( "HudClassHealth", 33 | { 34 | "name" : "TF2" 35 | "tall" : 16 36 | "weight" : 500 37 | "additive" : false 38 | "antialias" : true 39 | "proportional" : true 40 | } ); 41 | 42 | surface.CreateFont( "HudSelectionText", 43 | { 44 | "name" : "TF2" 45 | "tall" : 15 46 | "weight" : 700 47 | "antialias" : true 48 | "yres" : "1 599" 49 | "additive" : true 50 | } ); 51 | 52 | surface.CreateFont( "HudSelectionText", 53 | { 54 | "name" : "TF2" 55 | "tall" : 15 56 | "weight" : 700 57 | "antialias" : true 58 | "yres" : "600 767" 59 | "additive" : true 60 | } ); 61 | 62 | surface.CreateFont( "HudSelectionText", 63 | { 64 | "name" : "TF2" 65 | "tall" : 18 66 | "weight" : 900 67 | "antialias" : true 68 | "yres" : "768 1023" 69 | } ); 70 | 71 | surface.CreateFont( "HudSelectionText", 72 | { 73 | "name" : "TF2" 74 | "tall" : 21 75 | "weight" : 900 76 | "antialias" : true 77 | "yres" : "1024 1199" 78 | } ); 79 | 80 | surface.CreateFont( "HudSelectionText", 81 | { 82 | "name" : "TF2" 83 | "tall" : 24 84 | "weight" : 1000 85 | "antialias" : true 86 | "yres" : "1200 10000" 87 | } ); 88 | 89 | surface.CreateFont( "ItemFontNameLarge", 90 | { 91 | "name" : "TF2 Build" 92 | "tall" : 12 93 | "weight" : 500 94 | "additive" : false 95 | "antialias" : true 96 | "proportional" : true 97 | } ); 98 | 99 | surface.CreateFont( "ItemFontNameSmall", 100 | { 101 | "name" : "TF2 Build" 102 | "tall" : 9 103 | "weight" : 500 104 | "additive" : false 105 | "antialias" : true 106 | "proportional" : true 107 | } ); 108 | 109 | surface.CreateFont( "ItemFontNameSmallest", 110 | { 111 | "name" : "TF2 Build" 112 | "tall" : 8 113 | "weight" : 500 114 | "additive" : false 115 | "antialias" : true 116 | "proportional" : true 117 | } ); 118 | 119 | surface.CreateFont( "WeaponIcons", 120 | { 121 | "name" : "HalfLife2" 122 | "tall" : 36 123 | "weight" : 0 124 | "antialias" : true 125 | "additive" : true 126 | "custom" : true 127 | "proportional" : true 128 | } ); 129 | 130 | surface.CreateFont( "WeaponIconsSelected", 131 | { 132 | "name" : "HalfLife2" 133 | "tall" : 36 134 | "weight" : 0 135 | "antialias" : true 136 | "blur" : 5 137 | "scanlines" : 2 138 | "additive" : true 139 | "custom" : true 140 | "proportional" : true 141 | } ); 142 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_ammo.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudWeaponAmmo 9 | { 10 | self = null 11 | 12 | m_hAmmoBG = null 13 | //m_hLowAmmo = null 14 | 15 | m_hInClip = null 16 | m_hInClipShadow = null 17 | 18 | m_hInReserve = null 19 | m_hInReserveShadow = null 20 | 21 | m_hNoClip = null 22 | m_hNoClipShadow = null 23 | 24 | m_hSecondaryBG = null 25 | m_hSecondary = null 26 | m_hSecondaryShadow = null 27 | 28 | m_hWeapon = null 29 | m_nAmmo1 = -1 30 | m_nAmmo2 = -1 31 | m_nAmmoSecondary = -1 32 | } 33 | 34 | function CTFHudWeaponAmmo::Init() 35 | { 36 | self = vgui.CreatePanel( "Panel", TFHud.GetRootPanel(), "TFHudWeaponAmmo" ); 37 | self.SetZPos( 0 ); 38 | self.SetVisible( true ); 39 | self.SetPaintBackgroundEnabled( false ); 40 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 41 | self.SetCallback( "OnTick", OnTick.bindenv(this) ); 42 | self.AddTickSignal( 50 ); 43 | 44 | m_hAmmoBG = vgui.CreatePanel( "ImagePanel", self, "HudWeaponAmmoBG" ); 45 | m_hAmmoBG.SetVisible( true ); 46 | m_hAmmoBG.SetShouldScaleImage( true ); 47 | m_hAmmoBG.SetZPos( 1 ); 48 | // m_hAmmoBG.SetImage( "hud/ammo_red_bg", true ); 49 | 50 | //m_hLowAmmo = vgui.CreatePanel( "ImagePanel", self, "HudWeaponLowAmmoImage" ); 51 | //m_hLowAmmo.SetVisible( false ); 52 | //m_hLowAmmo.SetShouldScaleImage( true ); 53 | //m_hLowAmmo.SetZPos( 0 ); 54 | //m_hLowAmmo.SetImage( "hud/ammo_red_bg", true ); 55 | 56 | m_hInClip = vgui.CreatePanel( "Label", self, "AmmoInClip" ); 57 | m_hInClip.SetVisible( false ); 58 | m_hInClip.SetPaintBackgroundEnabled( false ); 59 | m_hInClip.SetZPos( 5 ); 60 | m_hInClip.SetFont( surface.GetFont( "HudFontGiantBold", true ) ); 61 | m_hInClip.SetContentAlignment( Alignment.southeast ); 62 | 63 | m_hInClipShadow = vgui.CreatePanel( "Label", self, "AmmoInClipShadow" ); 64 | m_hInClipShadow.SetVisible( false ); 65 | m_hInClipShadow.SetPaintBackgroundEnabled( false ); 66 | m_hInClipShadow.SetZPos( 5 ); 67 | m_hInClipShadow.SetFont( surface.GetFont( "HudFontGiantBold", true ) ); 68 | m_hInClipShadow.SetContentAlignment( Alignment.southeast ); 69 | 70 | m_hInReserve = vgui.CreatePanel( "Label", self, "AmmoInReserve" ); 71 | m_hInReserve.SetVisible( false ); 72 | m_hInReserve.SetPaintBackgroundEnabled( false ); 73 | m_hInReserve.SetZPos( 7 ); 74 | m_hInReserve.SetFont( surface.GetFont( "HudFontMediumSmall", true ) ); 75 | m_hInReserve.SetContentAlignment( Alignment.southwest ); 76 | 77 | m_hInReserveShadow = vgui.CreatePanel( "Label", self, "AmmoInReserveShadow" ); 78 | m_hInReserveShadow.SetVisible( false ); 79 | m_hInReserveShadow.SetPaintBackgroundEnabled( false ); 80 | m_hInReserveShadow.SetZPos( 7 ); 81 | m_hInReserveShadow.SetFont( surface.GetFont( "HudFontMediumSmall", true ) ); 82 | m_hInReserveShadow.SetContentAlignment( Alignment.southwest ); 83 | 84 | m_hNoClip = vgui.CreatePanel( "Label", self, "AmmoNoClip" ); 85 | m_hNoClip.SetVisible( false ); 86 | m_hNoClip.SetPaintBackgroundEnabled( false ); 87 | m_hNoClip.SetZPos( 5 ); 88 | m_hNoClip.SetFont( surface.GetFont( "HudFontGiantBold", true ) ); 89 | m_hNoClip.SetContentAlignment( Alignment.southeast ); 90 | 91 | m_hNoClipShadow = vgui.CreatePanel( "Label", self, "AmmoNoClipShadow" ); 92 | m_hNoClipShadow.SetVisible( false ); 93 | m_hNoClipShadow.SetPaintBackgroundEnabled( false ); 94 | m_hNoClipShadow.SetZPos( 5 ); 95 | m_hNoClipShadow.SetFont( surface.GetFont( "HudFontGiantBold", true ) ); 96 | m_hNoClipShadow.SetContentAlignment( Alignment.southeast ); 97 | 98 | m_hSecondaryBG = vgui.CreatePanel( "ImagePanel", TFHud.GetRootPanel(), "HudWeaponSecondaryAmmoBG" ); 99 | m_hSecondaryBG.SetVisible( false ); 100 | m_hSecondaryBG.SetShouldScaleImage( true ); 101 | m_hSecondaryBG.SetZPos( 1 ); 102 | 103 | m_hSecondary = vgui.CreatePanel( "Label", m_hSecondaryBG, "AmmoSecondary" ); 104 | m_hSecondary.SetVisible( true ); 105 | m_hSecondary.SetPaintBackgroundEnabled( false ); 106 | m_hSecondary.SetZPos( 5 ); 107 | m_hSecondary.SetFont( surface.GetFont( "HudFontMediumSmall", true ) ); 108 | m_hSecondary.SetContentAlignment( Alignment.center ); 109 | 110 | m_hSecondaryShadow = vgui.CreatePanel( "Label", m_hSecondaryBG, "AmmoSecondaryShadow" ); 111 | m_hSecondaryShadow.SetVisible( true ); 112 | m_hSecondaryShadow.SetPaintBackgroundEnabled( false ); 113 | m_hSecondaryShadow.SetZPos( 5 ); 114 | m_hSecondaryShadow.SetFont( surface.GetFont( "HudFontMediumSmall", true ) ); 115 | m_hSecondaryShadow.SetContentAlignment( Alignment.center ); 116 | } 117 | 118 | function CTFHudWeaponAmmo::PerformLayout() 119 | { 120 | // "Resource/HudLayout.res" 121 | self.SetPos( ScreenWidth() - YRES(95), ScreenHeight() - YRES(55) ); 122 | self.SetSize( YRES(94), YRES(45) ); 123 | 124 | // "Resource/UI/HudAmmoWeapons.res" 125 | m_hAmmoBG.SetPos( YRES(4), 0 ); 126 | m_hAmmoBG.SetSize( YRES(90), YRES(45) ); 127 | 128 | //m_hLowAmmo.SetPos( YRES(4), 0 ); 129 | //m_hLowAmmo.SetSize( YRES(90), YRES(45) ); 130 | //m_hLowAmmo.SetDrawColor( 255, 0, 0, 255 ); 131 | 132 | // Must be set-up to set colours of invisible panels 133 | m_hInClip.MakeReadyForUse(); 134 | m_hInClipShadow.MakeReadyForUse(); 135 | m_hInReserve.MakeReadyForUse(); 136 | m_hInReserveShadow.MakeReadyForUse(); 137 | m_hNoClip.MakeReadyForUse(); 138 | m_hNoClipShadow.MakeReadyForUse(); 139 | m_hSecondary.MakeReadyForUse(); 140 | m_hSecondaryShadow.MakeReadyForUse(); 141 | 142 | m_hInClip.SetPos( YRES(4), 0 ); 143 | m_hInClip.SetSize( YRES(55), YRES(40) ); 144 | m_hInClip.SetFgColor( 235, 226, 202, 255 ); 145 | 146 | m_hInClipShadow.SetPos( YRES(5), YRES(1) ); 147 | m_hInClipShadow.SetSize( YRES(55), YRES(40) ); 148 | m_hInClipShadow.SetFgColor( 46, 43, 42, 255 ); 149 | 150 | m_hInReserve.SetPos( YRES(59), YRES(8) ); 151 | m_hInReserve.SetSize( YRES(40), YRES(27) ); 152 | m_hInReserve.SetFgColor( 235, 226, 202, 255 ); 153 | 154 | m_hInReserveShadow.SetPos( YRES(60), YRES(9) ); 155 | m_hInReserveShadow.SetSize( YRES(40), YRES(27) ); 156 | m_hInReserveShadow.SetFgColor( 0, 0, 0, 196 ); 157 | 158 | m_hNoClip.SetPos( 0, YRES(2) ); 159 | m_hNoClip.SetSize( YRES(84), YRES(40) ); 160 | m_hNoClip.SetFgColor( 235, 226, 202, 255 ); 161 | 162 | m_hNoClipShadow.SetPos( YRES(1), YRES(3) ); 163 | m_hNoClipShadow.SetSize( YRES(84), YRES(40) ); 164 | m_hNoClipShadow.SetFgColor( 46, 43, 42, 255 ); 165 | 166 | // Custom hud element 167 | // small secondary ammo display 168 | m_hSecondaryBG.SetSize( YRES(90*0.66), YRES(45*0.66) ); 169 | m_hSecondaryBG.SetPos( ScreenWidth() - YRES(45 + 4), ScreenHeight() - YRES(100 - 45*0.33) ); 170 | 171 | m_hSecondary.SetPos( 0, YRES(2) ); 172 | m_hSecondary.SetSize( YRES(84*0.66), YRES(40*0.66) ); 173 | m_hSecondary.SetFgColor( 235, 226, 202, 255 ); 174 | 175 | m_hSecondaryShadow.SetPos( YRES(1), YRES(3) ); 176 | m_hSecondaryShadow.SetSize( YRES(84*0.66), YRES(40*0.66) ); 177 | m_hSecondaryShadow.SetFgColor( 46, 43, 42, 255 ); 178 | } 179 | 180 | function CTFHudWeaponAmmo::OnTick() 181 | { 182 | local weapon = player.GetActiveWeapon(); 183 | 184 | if ( !weapon ) 185 | { 186 | if ( m_hWeapon ) 187 | { 188 | SetVisibleInClip( false ); 189 | SetVisibleInReserve( false ); 190 | SetVisibleNoClip( false ); 191 | SetVisibleSecondary( false ); 192 | // m_hLowAmmo.SetVisible( false ); 193 | 194 | m_nAmmo1 = m_nAmmo2 = -1; 195 | m_hWeapon = null; 196 | } 197 | return; 198 | } 199 | 200 | local nAmmo1 = weapon.Clip1(); 201 | local nAmmo2 = 0; 202 | if ( nAmmo1 == -1 ) 203 | { 204 | nAmmo1 = player.GetAmmoCount( weapon.GetPrimaryAmmoType() ); 205 | } 206 | else 207 | { 208 | nAmmo2 = player.GetAmmoCount( weapon.GetPrimaryAmmoType() ); 209 | } 210 | 211 | local nAmmoSecondary = -1; 212 | if ( weapon.UsesSecondaryAmmo() ) 213 | { 214 | nAmmoSecondary = player.GetAmmoCount( weapon.GetSecondaryAmmoType() ); 215 | } 216 | 217 | // update on change 218 | if ( m_hWeapon != weapon || nAmmo1 != m_nAmmo1 || nAmmo2 != m_nAmmo2 || nAmmoSecondary != m_nAmmoSecondary ) 219 | { 220 | m_hWeapon = weapon; 221 | m_nAmmo1 = nAmmo1; 222 | m_nAmmo2 = nAmmo2; 223 | m_nAmmoSecondary = nAmmoSecondary; 224 | 225 | if ( weapon.UsesPrimaryAmmo() ) 226 | { 227 | if ( weapon.UsesClipsForAmmo1() ) 228 | { 229 | SetAmmoInClip( nAmmo1 ); 230 | SetAmmoInReserve( nAmmo2 ); 231 | 232 | if ( !m_hInClip.IsVisible() ) 233 | { 234 | SetVisibleInClip( true ); 235 | SetVisibleInReserve( true ); 236 | SetVisibleNoClip( false ); 237 | } 238 | } 239 | else 240 | { 241 | SetAmmoNoClip( nAmmo1 ); 242 | 243 | if ( !m_hNoClip.IsVisible() ) 244 | { 245 | SetVisibleInClip( false ); 246 | SetVisibleInReserve( false ); 247 | SetVisibleNoClip( true ); 248 | } 249 | } 250 | 251 | if ( nAmmoSecondary != -1 ) 252 | { 253 | SetAmmoSecondary( nAmmoSecondary ); 254 | 255 | if ( !m_hSecondaryBG.IsVisible() ) 256 | { 257 | SetVisibleSecondary( true ); 258 | } 259 | } 260 | else 261 | { 262 | if ( m_hSecondaryBG.IsVisible() ) 263 | { 264 | SetVisibleSecondary( false ); 265 | } 266 | } 267 | } 268 | // Only uses secondary ammo, set primary ammo invisible, draw secondary ammo if it's not invalid. 269 | // weapon_slam does this... 270 | else if ( nAmmoSecondary != -1 ) 271 | { 272 | SetAmmoSecondary( nAmmoSecondary ); 273 | 274 | if ( !m_hSecondaryBG.IsVisible() ) 275 | { 276 | SetVisibleSecondary( true ); 277 | } 278 | 279 | if ( m_hInClip.IsVisible() || m_hNoClip.IsVisible() ) 280 | { 281 | SetVisibleInClip( false ); 282 | SetVisibleInReserve( false ); 283 | SetVisibleNoClip( false ); 284 | } 285 | } 286 | else 287 | { 288 | if ( m_hInClip.IsVisible() || m_hNoClip.IsVisible() || m_hSecondaryBG.IsVisible() ) 289 | { 290 | SetVisibleInClip( false ); 291 | SetVisibleInReserve( false ); 292 | SetVisibleNoClip( false ); 293 | SetVisibleSecondary( false ); 294 | } 295 | } 296 | } 297 | } 298 | 299 | function CTFHudWeaponAmmo::SetAmmoInClip( nAmt ) 300 | { 301 | local text = "" + nAmt; 302 | m_hInClip.SetText( text ); 303 | return m_hInClipShadow.SetText( text ); 304 | } 305 | 306 | function CTFHudWeaponAmmo::SetAmmoInReserve( nAmt ) 307 | { 308 | local text = "" + nAmt; 309 | m_hInReserve.SetText( text ); 310 | return m_hInReserveShadow.SetText( text ); 311 | } 312 | 313 | function CTFHudWeaponAmmo::SetAmmoNoClip( nAmt ) 314 | { 315 | local text = "" + nAmt; 316 | m_hNoClip.SetText( text ); 317 | return m_hNoClipShadow.SetText( text ); 318 | } 319 | 320 | function CTFHudWeaponAmmo::SetAmmoSecondary( nAmt ) 321 | { 322 | local text = "" + nAmt; 323 | m_hSecondary.SetText( text ); 324 | return m_hSecondaryShadow.SetText( text ); 325 | } 326 | 327 | function CTFHudWeaponAmmo::SetVisibleInClip( state ) 328 | { 329 | m_hInClip.SetVisible( state ); 330 | return m_hInClipShadow.SetVisible( state ); 331 | } 332 | 333 | function CTFHudWeaponAmmo::SetVisibleInReserve( state ) 334 | { 335 | m_hInReserve.SetVisible( state ); 336 | return m_hInReserveShadow.SetVisible( state ); 337 | } 338 | 339 | function CTFHudWeaponAmmo::SetVisibleNoClip( state ) 340 | { 341 | m_hNoClip.SetVisible( state ); 342 | return m_hNoClipShadow.SetVisible( state ); 343 | } 344 | 345 | function CTFHudWeaponAmmo::SetVisibleSecondary( state ) 346 | { 347 | return m_hSecondaryBG.SetVisible( state ); 348 | } 349 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_flashlight.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudFlashlight 9 | { 10 | self = null 11 | m_hEffectMeter = null 12 | m_hEffectMeterBG = null 13 | m_hEffectMeterLabel = null 14 | m_flFlashlight = 0.0 15 | } 16 | 17 | function CTFHudFlashlight::Init() 18 | { 19 | self = vgui.CreatePanel( "ImagePanel", TFHud.GetRootPanel(), "ItemEffectMeterBG" ) 20 | self.SetZPos( 0 ); 21 | self.SetVisible( false ); 22 | self.SetShouldScaleImage( true ); 23 | // self.SetImage( "hud/misc_ammo_area_horiz1_red", true ); 24 | 25 | m_hEffectMeterLabel = vgui.CreatePanel( "Label", self, "ItemEffectMeterLabel" ) 26 | m_hEffectMeterLabel.SetZPos( 2 ); 27 | m_hEffectMeterLabel.SetVisible( true ); 28 | m_hEffectMeterLabel.SetPaintBackgroundEnabled( false ); 29 | m_hEffectMeterLabel.SetContentAlignment( Alignment.center ); 30 | m_hEffectMeterLabel.SetFont( surface.GetFont( "TFFontSmall", true ) ); 31 | m_hEffectMeterLabel.SetText( "TORCH" ); 32 | 33 | m_hEffectMeter = vgui.CreatePanel( "Panel", self, "ItemEffectMeter" ) 34 | m_hEffectMeter.SetZPos( 2 ); 35 | m_hEffectMeter.SetVisible( true ); 36 | m_hEffectMeter.SetPaintEnabled( true ); 37 | m_hEffectMeter.SetPaintBackgroundEnabled( false ); 38 | m_hEffectMeter.SetCallback( "Paint", PaintProgressBar.bindenv(this) ); 39 | m_hEffectMeter.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 40 | 41 | m_flFlashlight = 1.0; 42 | } 43 | 44 | function CTFHudFlashlight::PaintProgressBar() 45 | { 46 | local w = m_hEffectMeter.GetWide(); 47 | local t = m_hEffectMeter.GetTall(); 48 | 49 | surface.SetColor( 0xff, 0xff, 0xff, 0x1f ); 50 | surface.DrawFilledRect( 0, 0, w, t ); 51 | 52 | if ( m_flFlashlight > 0.25 ) 53 | { 54 | surface.SetColor( 0xff, 0xff, 0xff, 0xff ); 55 | } 56 | else 57 | { 58 | surface.SetColor( 0xff, 0x33, 0, 0xff ); 59 | } 60 | 61 | surface.DrawFilledRect( 0, 0, w * m_flFlashlight, t ); 62 | } 63 | 64 | function CTFHudFlashlight::PerformLayout() 65 | { 66 | // "Resource/UI/HudItemEffectMeter.res" 67 | 68 | // Uses the ImagePanel as the base 69 | local offX = YRES(12); 70 | local offY = YRES(6); 71 | 72 | self.SetPos( ScreenWidth() - YRES(174) + offX, ScreenHeight() - YRES(62) + offY ); 73 | self.SetSize( YRES(100), YRES(50) ); 74 | 75 | m_hEffectMeterLabel.SetPos( YRES(42) - offX, YRES(30) - offY ); 76 | m_hEffectMeterLabel.SetSize( YRES(41), YRES(15) ); 77 | 78 | m_hEffectMeter.SetPos( YRES(47) - offX, YRES(28) - offY ); 79 | m_hEffectMeter.SetSize( YRES(30), YRES(5) ); 80 | } 81 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_health.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudPlayerHealth 9 | { 10 | self = null 11 | m_hBleedImage = null 12 | m_hHealthImageBG = null 13 | m_hHealthBonusImage = null 14 | m_hHealthImage = null 15 | m_hHealthValue = null 16 | m_hArmorValue = null 17 | 18 | m_iHealthTex = null 19 | m_iDeadTex = null 20 | 21 | m_flMaxHealth = 0.0 22 | m_nHealth = 0 23 | m_flHealth = 0.0 24 | m_nArmor = 0 25 | 26 | m_nHealthWarningThreshold = 0 27 | 28 | m_iHealthFlash = 1 29 | m_iHealthFlashAlpha = 255 30 | m_flFlashStartTime = 0.0 31 | 32 | m_bBleeding = false 33 | } 34 | 35 | function CTFHudPlayerHealth::Init() 36 | { 37 | self = vgui.CreatePanel( "Panel", TFHud.m_pPlayerStatus.self, "HudPlayerHealth" ); 38 | self.SetZPos( 2 ); 39 | self.SetVisible( true ); 40 | self.SetPaintBackgroundEnabled( false ); 41 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 42 | self.SetCallback( "OnTick", OnTick.bindenv(this) ); 43 | self.AddTickSignal( 100 ); 44 | 45 | m_hBleedImage = vgui.CreatePanel( "ImagePanel", self, "PlayerStatusBleedImage" ); 46 | m_hBleedImage.SetVisible( false ); 47 | m_hBleedImage.SetShouldScaleImage( true ); 48 | m_hBleedImage.SetZPos( 7 ); 49 | m_hBleedImage.SetImage( "vgui/bleed_drop", true ); 50 | 51 | m_hHealthImageBG = vgui.CreatePanel( "ImagePanel", self, "PlayerStatusHealthImageBG" ); 52 | m_hHealthImageBG.SetVisible( true ); 53 | m_hHealthImageBG.SetShouldScaleImage( true ); 54 | m_hHealthImageBG.SetZPos( 3 ); 55 | m_hHealthImageBG.SetImage( "hud/health_bg", true ); 56 | 57 | m_hHealthBonusImage = vgui.CreatePanel( "ImagePanel", self, "PlayerStatusHealthBonusImage" ); 58 | m_hHealthBonusImage.SetVisible( false ); 59 | m_hHealthBonusImage.SetShouldScaleImage( true ); 60 | m_hHealthBonusImage.SetZPos( 2 ); 61 | m_hHealthBonusImage.SetImage( "hud/health_over_bg", true ); 62 | 63 | m_hHealthImage = vgui.CreatePanel( "Panel", self, "PlayerStatusHealthImage" ); 64 | m_hHealthImage.SetVisible( true ); 65 | m_hHealthImage.SetPaintBackgroundEnabled( false ); 66 | m_hHealthImage.SetZPos( 4 ); 67 | m_hHealthImage.SetCallback( "Paint", HealthPaint.bindenv(this) ); 68 | 69 | m_iHealthTex = surface.ValidateTexture( "hud/health_color", true ); 70 | m_iDeadTex = surface.ValidateTexture( "hud/health_dead", true ); 71 | 72 | m_hHealthValue = vgui.CreatePanel( "Label", self, "PlayerStatusHealthValue" ); 73 | m_hHealthValue.SetVisible( true ); 74 | m_hHealthValue.SetPaintBackgroundEnabled( false ); 75 | m_hHealthValue.SetFont( surface.GetFont( "HudClassHealth", true ) ); 76 | m_hHealthValue.SetContentAlignment( Alignment.center ); 77 | m_hHealthValue.SetZPos( 5 ); 78 | 79 | m_hArmorValue = vgui.CreatePanel( "Label", self, "PlayerStatusArmorValue" ); 80 | m_hArmorValue.SetVisible( true ); 81 | m_hArmorValue.SetPaintBackgroundEnabled( false ); 82 | m_hArmorValue.SetFont( surface.GetFont( "HudClassHealth", true ) ); 83 | m_hArmorValue.SetContentAlignment( Alignment.center ); 84 | m_hArmorValue.SetZPos( 5 ); 85 | } 86 | 87 | function CTFHudPlayerHealth::PerformLayout() 88 | { 89 | TFHud.m_hCrosshair.SetSize( 32, 32 ); 90 | TFHud.m_hCrosshair.SetPos( XRES(320) - 16, YRES(240) - 16 ); 91 | 92 | // "Resource/UI/HudPlayerHealth.res" 93 | self.SetPos( 0, ScreenHeight() - YRES(120) ); 94 | self.SetSize( YRES(250), YRES(120) ); 95 | 96 | m_hBleedImage.SetPos( YRES(85), YRES(0) ); 97 | m_hBleedImage.SetSize( YRES(32), YRES(32) ); 98 | 99 | m_hHealthImageBG.SetPos( YRES(73), YRES(33) ); 100 | m_hHealthImageBG.SetSize( YRES(55), YRES(55) ); 101 | 102 | m_hHealthBonusImage.SetPos( YRES(73), YRES(33) ); 103 | m_hHealthBonusImage.SetSize( YRES(55), YRES(55) ); 104 | 105 | m_hHealthImage.SetPos( YRES(75), YRES(35) ); 106 | m_hHealthImage.SetSize( YRES(51), YRES(51) ); 107 | 108 | m_hHealthValue.SetPos( YRES(76), YRES(52) ); 109 | m_hHealthValue.SetSize( YRES(50), YRES(18) ); 110 | m_hHealthValue.SetFgColor( 117, 107, 94, 255 ); 111 | 112 | m_hArmorValue.SetPos( YRES(76), m_hHealthImage.GetYPos() - YRES(18) - YRES(2) ); 113 | m_hArmorValue.SetSize( YRES(50), YRES(18) ); 114 | m_hArmorValue.SetFgColor( 117, 107, 94, 255 ); 115 | 116 | // Update visibility 117 | OnTick(); 118 | } 119 | 120 | function CTFHudPlayerHealth::OnTick() 121 | { 122 | local nHealth = player.GetHealth(); 123 | 124 | if ( nHealth < 0 ) 125 | { 126 | nHealth = 0; 127 | } 128 | else 129 | { 130 | m_hArmorValue.SetText( "" + m_nArmor ); 131 | } 132 | 133 | if ( nHealth == m_nHealth ) 134 | return; 135 | 136 | m_nHealth = nHealth; 137 | m_flHealth = 1.0 - nHealth / m_flMaxHealth; 138 | 139 | if ( nHealth > 0 ) 140 | { 141 | if ( nHealth < m_nHealthWarningThreshold ) 142 | { 143 | m_hHealthBonusImage.SetDrawColor( 255, 0, 0, 255 ); 144 | 145 | local offsetPos = 35.0 * m_flHealth * m_flHealth; 146 | local offsetSize = 2.0 * offsetPos; 147 | 148 | m_hHealthBonusImage.SetPos( 149 | m_hHealthImageBG.GetXPos() - offsetPos, 150 | m_hHealthImageBG.GetYPos() - offsetPos ); 151 | m_hHealthBonusImage.SetSize( 152 | m_hHealthImageBG.GetWide() + offsetSize, 153 | m_hHealthImageBG.GetTall() + offsetSize ); 154 | 155 | if ( !m_hHealthBonusImage.IsVisible() ) 156 | { 157 | m_flFlashStartTime = Time(); 158 | 159 | m_hHealthBonusImage.SetVisible( true ); 160 | m_iHealthFlashAlpha = 255; 161 | m_iHealthFlash = 1; 162 | } 163 | } 164 | else 165 | { 166 | m_hHealthBonusImage.SetVisible( false ); 167 | } 168 | 169 | m_hHealthValue.SetText( "" + nHealth ); 170 | } 171 | else 172 | { 173 | m_hHealthImageBG.SetVisible( false ); 174 | m_hHealthBonusImage.SetVisible( false ); 175 | m_hHealthValue.SetText( "" ); 176 | } 177 | } 178 | 179 | function CTFHudPlayerHealth::HealthPaint() 180 | { 181 | local w = m_hHealthImage.GetWide(); 182 | local h = m_hHealthImage.GetTall(); 183 | 184 | if ( m_nHealth > 0 ) 185 | { 186 | if ( m_nHealth < m_nHealthWarningThreshold ) 187 | { 188 | surface.SetColor( 255, 0, 0, 255 ); 189 | } 190 | else 191 | { 192 | surface.SetColor( 255, 255, 255, 255 ); 193 | } 194 | 195 | surface.SetTexture( m_iHealthTex ); 196 | 197 | local fh = m_flHealth; 198 | surface.DrawTexturedSubRect( 0, fh * h, w, h, 0.0, fh, 1.0, 1.0 ); 199 | } 200 | else 201 | { 202 | surface.SetColor( 255, 255, 255, 255 ); 203 | surface.SetTexture( m_iDeadTex ); 204 | surface.DrawTexturedRect( 0, 0, w, h ); 205 | } 206 | } 207 | 208 | function CTFHudPlayerHealth::AnimThink() 209 | { 210 | if ( m_nHealth < m_nHealthWarningThreshold ) 211 | { 212 | if ( m_iHealthFlash ) 213 | { 214 | local a = m_iHealthFlashAlpha -= 64; 215 | m_hHealthBonusImage.SetAlpha( a ); 216 | 217 | if ( a <= 0 ) 218 | { 219 | m_iHealthFlash = 0; 220 | } 221 | } 222 | else 223 | { 224 | local a = m_iHealthFlashAlpha += 64; 225 | m_hHealthBonusImage.SetAlpha( a ); 226 | 227 | if ( a >= 255 ) 228 | { 229 | m_iHealthFlash = 1; 230 | } 231 | } 232 | } 233 | 234 | if ( m_bBleeding ) 235 | { 236 | local pulse = ( ( Time() * 10.0 ).tointeger() % 5 ) * 10; 237 | m_hBleedImage.SetDrawColor( 125 + pulse, 0, 0, 255 ); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_playerclass.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudPlayerClass 9 | { 10 | self = null 11 | m_hClassImage = null 12 | m_hClassImageBG = null 13 | } 14 | 15 | function CTFHudPlayerClass::Init() 16 | { 17 | self = vgui.CreatePanel( "Panel", TFHud.m_pPlayerStatus.self, "HudPlayerClass" ); 18 | self.SetZPos( 1 ); 19 | self.SetVisible( true ); 20 | self.SetPaintBackgroundEnabled( false ); 21 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 22 | 23 | m_hClassImage = vgui.CreatePanel( "ImagePanel", self, "PlayerStatusClassImage" ) 24 | m_hClassImage.SetZPos( 2 ); 25 | m_hClassImage.SetVisible( true ); 26 | m_hClassImage.SetShouldScaleImage( true ); 27 | // m_hClassImage.SetImage( "hud/class_spyred", true ); 28 | 29 | m_hClassImageBG = vgui.CreatePanel( "ImagePanel", self, "PlayerStatusClassImageBG" ) 30 | m_hClassImageBG.SetZPos( 1 ); 31 | m_hClassImageBG.SetVisible( true ); 32 | m_hClassImageBG.SetShouldScaleImage( true ); 33 | // m_hClassImageBG.SetImage( "hud/character_red_bg", true ); 34 | } 35 | 36 | function CTFHudPlayerClass::PerformLayout() 37 | { 38 | // "Resource/UI/HudPlayerClass.res" 39 | self.SetPos( 0, 0 ); 40 | self.SetSize( YRES(480), YRES(480) ); 41 | 42 | m_hClassImage.SetPos( YRES(25), self.GetTall() - YRES(88) ); 43 | m_hClassImage.SetSize( YRES(75), YRES(75) ); 44 | 45 | m_hClassImageBG.SetPos( YRES(9), self.GetTall() - YRES(60) ); 46 | m_hClassImageBG.SetSize( YRES(100), YRES(50) ); 47 | } 48 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_playerstatus.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudPlayerStatus 9 | { 10 | self = null 11 | } 12 | 13 | function CTFHudPlayerStatus::Init() 14 | { 15 | self = vgui.CreatePanel( "Panel", TFHud.GetRootPanel(), "TFHudPlayerStatus" ); 16 | self.SetVisible( true ); 17 | self.SetPaintBackgroundEnabled( false ); 18 | self.SetZPos( -100 ); 19 | self.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 20 | } 21 | 22 | function CTFHudPlayerStatus::PerformLayout() 23 | { 24 | // "Resource/HudLayout.res" 25 | self.SetPos( 0, 0 ); 26 | self.SetSize( YRES(480), YRES(480) ); 27 | } 28 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_scope.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | local surface = surface, NetProps = NetProps; 7 | 8 | 9 | class CTFHudScope 10 | { 11 | self = null 12 | 13 | m_bVisible = false 14 | 15 | m_hScopeTex0 = null 16 | m_hScopeTex1 = null 17 | m_hScopeTex2 = null 18 | m_hScopeTex3 = null 19 | } 20 | 21 | function CTFHudScope::Init() 22 | { 23 | self = vgui.CreatePanel( "Panel", TFHud.GetRootPanel(), "TFHudScope" ); 24 | self.SetSize( ScreenWidth(), ScreenHeight() ); 25 | self.SetZPos( -101 ); 26 | self.SetVisible( m_bVisible ); 27 | self.SetPaintEnabled( true ); 28 | self.SetPaintBackgroundEnabled( false ); 29 | self.SetCallback( "Paint", Paint.bindenv(this) ); 30 | 31 | m_hScopeTex0 = surface.ValidateTexture( "hud/scope_sniper_lr", true ); 32 | m_hScopeTex1 = surface.ValidateTexture( "hud/scope_sniper_ll", true ); 33 | m_hScopeTex2 = surface.ValidateTexture( "hud/scope_sniper_ul", true ); 34 | m_hScopeTex3 = surface.ValidateTexture( "hud/scope_sniper_ur", true ); 35 | } 36 | 37 | function CTFHudScope::Paint() 38 | { 39 | local wide = XRES(640); 40 | local tall = YRES(480); 41 | local wideHalf = wide / 2; 42 | local tallHalf = tall / 2; 43 | local texTall = tallHalf; 44 | 45 | local texWide = texTall * 4.0 / 3.0; 46 | local x0 = wideHalf - texWide; 47 | 48 | surface.SetColor( 0, 0, 0, 255 ); 49 | surface.SetTexture( m_hScopeTex0 ); 50 | surface.DrawTexturedRect( wideHalf, tallHalf, texWide, texTall ); 51 | 52 | surface.SetTexture( m_hScopeTex1 ); 53 | surface.DrawTexturedRect( x0, tallHalf, texWide, texTall ); 54 | 55 | surface.SetTexture( m_hScopeTex2 ); 56 | surface.DrawTexturedRect( x0, 0, texWide, texTall ); 57 | 58 | surface.SetTexture( m_hScopeTex3 ); 59 | surface.DrawTexturedRect( wideHalf, 0, texWide, texTall ); 60 | 61 | surface.DrawFilledRect( 0, 0, x0, tall ); 62 | surface.DrawFilledRect( wideHalf + texWide, 0, x0, tall ); 63 | } 64 | 65 | function CTFHudScope::SetVisible( state ) 66 | { 67 | m_bVisible = state; 68 | return self.SetVisible( state ); 69 | } 70 | -------------------------------------------------------------------------------- /mapbase/tf_hud/hud_tf_suitpower.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | local XRES = XRES, YRES = YRES; 6 | 7 | 8 | class CTFHudSuitPower 9 | { 10 | self = null 11 | m_hEffectMeter = null 12 | m_hEffectMeterBG = null 13 | m_hEffectMeterLabel = null 14 | m_flPower = 0.0 15 | } 16 | 17 | function CTFHudSuitPower::Init() 18 | { 19 | self = vgui.CreatePanel( "ImagePanel", TFHud.GetRootPanel(), "SuitPowerMeterBG" ) 20 | self.SetZPos( 0 ); 21 | self.SetVisible( false ); 22 | self.SetShouldScaleImage( true ); 23 | // self.SetImage( "hud/misc_ammo_area_red", true ); 24 | 25 | m_hEffectMeterLabel = vgui.CreatePanel( "Label", self, "ItemEffectMeterLabel" ) 26 | m_hEffectMeterLabel.SetZPos( 2 ); 27 | m_hEffectMeterLabel.SetVisible( true ); 28 | m_hEffectMeterLabel.SetPaintBackgroundEnabled( false ); 29 | m_hEffectMeterLabel.SetContentAlignment( Alignment.center ); 30 | m_hEffectMeterLabel.SetFont( surface.GetFont( "TFFontSmall", true ) ); 31 | m_hEffectMeterLabel.SetText( "AUX" ); 32 | 33 | m_hEffectMeter = vgui.CreatePanel( "Panel", self, "ItemEffectMeter" ) 34 | m_hEffectMeter.SetZPos( 2 ); 35 | m_hEffectMeter.SetVisible( true ); 36 | m_hEffectMeter.SetPaintEnabled( true ); 37 | m_hEffectMeter.SetPaintBackgroundEnabled( false ); 38 | m_hEffectMeter.SetCallback( "Paint", PaintProgressBar.bindenv(this) ); 39 | m_hEffectMeter.SetCallback( "PerformLayout", PerformLayout.bindenv(this) ); 40 | 41 | m_flPower = 1.0; 42 | } 43 | 44 | function CTFHudSuitPower::PaintProgressBar() 45 | { 46 | local w = m_hEffectMeter.GetWide(); 47 | local t = m_hEffectMeter.GetTall(); 48 | 49 | surface.SetColor( 0xff, 0xff, 0xff, 0x1f ); 50 | surface.DrawFilledRect( 0, 0, w, t ); 51 | 52 | if ( m_flPower > 0.25 ) 53 | { 54 | surface.SetColor( 0xff, 0xff, 0xff, 0xff ); 55 | } 56 | else 57 | { 58 | surface.SetColor( 0xff, 0x33, 0, 0xff ); 59 | } 60 | 61 | surface.DrawFilledRect( 0, 0, w * m_flPower, t ); 62 | } 63 | 64 | function CTFHudSuitPower::PerformLayout() 65 | { 66 | local offX = YRES(12); 67 | 68 | self.SetPos( YRES(128), ScreenHeight() - YRES(62) + YRES(6) ); 69 | self.SetSize( YRES(76), YRES(44) ); 70 | 71 | m_hEffectMeterLabel.SetPos( YRES(25) - offX, YRES(27) ); 72 | m_hEffectMeterLabel.SetSize( YRES(41), YRES(15) ); 73 | 74 | m_hEffectMeter.SetPos( YRES(25) - offX, YRES(23) ); 75 | m_hEffectMeter.SetSize( YRES(40), YRES(6) ); 76 | } 77 | -------------------------------------------------------------------------------- /mapbase/tf_hud/init.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // Team Fortress 2 HUD 6 | // 7 | // TFHud.SetPlayerClass( enum TFTEAM nTeam, enum TFPlayerClass nClass ) 8 | // TFHud.SetBleeding( bool state ) 9 | // TFHud.SetCrosshairVisible( bool state ) 10 | // TFHud.SetCrosshairImage( string imageFile, string weaponClassname = null ) 11 | // 12 | //------------------------------------------------------------- 13 | // Resource files: [tf] 14 | // "resources/tf2.ttf" 15 | // "resources/tf2build.ttf" 16 | // tf/materials 17 | //------------------------------------------------------------- 18 | 19 | 20 | enum TFTEAM 21 | { 22 | NONE, 23 | RED, 24 | BLUE 25 | } 26 | 27 | enum TFPlayerClass 28 | { 29 | NONE, 30 | SCOUT, 31 | SOLDIER, 32 | PYRO, 33 | DEMOMAN, 34 | HEAVY, 35 | ENGINEER, 36 | MEDIC, 37 | SNIPER, 38 | SPY 39 | } 40 | 41 | const TF2HUD_VERSION = 23111300; 42 | 43 | // Automatically detect the subdirectory. 44 | // Does not work if it was loaded with DoIncludeScript() 45 | local TF2HUD_PATH = "tf_hud/"; 46 | local si = getstackinfos(3); 47 | if ( si ) 48 | { 49 | foreach ( k, v in si.locals ) 50 | { 51 | local i; 52 | if ( ( typeof v == "string" ) && ( ( i = v.find("init") ) != null ) ) 53 | { 54 | TF2HUD_PATH = v.slice( 0, i ); 55 | break; 56 | } 57 | } 58 | } 59 | 60 | local CONST = getconsttable(); 61 | CONST.TF2HUD_PATH <- TF2HUD_PATH; 62 | 63 | local Init = function(...) 64 | { 65 | if ( CLIENT_DLL ) 66 | IncludeScript( TF2HUD_PATH + "fonts.nut" ); 67 | 68 | if ( !("TFHud" in this) ) // Level transition (OnRestore) 69 | IncludeScript( TF2HUD_PATH + "hud_tf.nut" ); 70 | 71 | if ( SERVER_DLL ) 72 | { 73 | TFHud.Init( vargv[0] ); 74 | } 75 | else // CLIENT_DLL 76 | { 77 | NetMsg.Receive( "TFHud.Load", null ); 78 | TFHud.Init(); 79 | } 80 | } 81 | 82 | ListenToGameEvent( "player_spawn", function( event ) 83 | { 84 | if ( SERVER_DLL ) 85 | { 86 | Init( GetPlayerByUserID( event.userid ) ); 87 | } 88 | else // CLIENT_DLL 89 | { 90 | Init(); 91 | Entities.First().SetContextThink( "TFHud", function(_) { StopListeningToAllGameEvents( "TFHud" ); }, 0.01 ); 92 | } 93 | }, "TFHud" ); 94 | 95 | // Save/restore 96 | { 97 | local InitRestore = function(...) 98 | { 99 | if ( SERVER_DLL ) 100 | { 101 | Init( Entities.GetLocalPlayer() ); 102 | } 103 | else // CLIENT_DLL 104 | { 105 | // Level transition hack 106 | Entities.First().SetContextThink( "TFHud", Init, 0.0 ); 107 | } 108 | } 109 | 110 | Hooks.Add( this, "OnRestore", InitRestore, "TFHud" ); 111 | 112 | // Handle loads on saves that were not saved with this HUD 113 | if ( SERVER_DLL ) 114 | { 115 | local t = GetLoadType(); 116 | if ( t == MapLoad.LoadGame || t == MapLoad.Transition ) 117 | { 118 | Entities.First().SetContextThink( "TFHud.Load", function(_) 119 | { 120 | // This is not well tested 121 | if ( "TFHud" in getroottable() ) 122 | { 123 | local reload = 0; 124 | 125 | if ( "version" in TFHud ) 126 | { 127 | // Save is more recent, don't reload 128 | if ( TFHud.version >= TF2HUD_VERSION ) 129 | return; 130 | 131 | reload = 1; 132 | } 133 | else 134 | { 135 | if ( "StatusUpdate2" in TFHud ) // StatusUpdate2 was added in the same update as cs_hud_reload 136 | { 137 | reload = 1; 138 | } 139 | else 140 | { 141 | // Do nothing, the added complexity to reload this version is not worth it. 142 | print( "This save file includes an ancient version of TFHud. Not updating.\n" ); 143 | return; 144 | } 145 | } 146 | 147 | if ( reload ) 148 | { 149 | if ( "version" in TFHud ) 150 | { 151 | printf( "Updating TFHud to %i (from %i)\n", TF2HUD_VERSION, TFHud.version ); 152 | } 153 | else 154 | { 155 | printf( "Updating TFHud to %i\n", TF2HUD_VERSION ); 156 | } 157 | 158 | // Wait for player to spawn 159 | Entities.First().SetContextThink( "TFHud.Load2", function(_) 160 | { 161 | SendToConsole( "tf_hud_reload" ); 162 | }, 0.25 ); 163 | } 164 | 165 | // Let client handle the reload 166 | return; 167 | } 168 | else 169 | { 170 | print( "This save file does not include TFHud, loading...\n" ); 171 | } 172 | 173 | Hooks.Add( this, "OnRestore", InitRestore, "TFHud" ); 174 | 175 | local player = Entities.GetLocalPlayer(); 176 | Init( player ); 177 | NetMsg.Start( "TFHud.Load" ); 178 | NetMsg.Send( player, true ); 179 | }, 0.1 ); 180 | } 181 | } 182 | else // CLIENT_DLL 183 | { 184 | // Hooks are reset on save restore because hook functions are stored in the VM. 185 | // NetMsg functions are not reset because they are stored in C++. 186 | // Hence the need to re-register the hook but not the net messages. 187 | NetMsg.Receive( "TFHud.Load", function() 188 | { 189 | Hooks.Add( this, "OnRestore", InitRestore, "TFHud" ); 190 | Init(); 191 | } ); 192 | } 193 | } 194 | 195 | if ( !("GetPlayerByUserID" in this) ) 196 | { 197 | function GetPlayerByUserID(i) 198 | { 199 | for ( local p; p = Entities.FindByClassname( p, "player" ); ) 200 | if ( p.GetUserID() == i ) 201 | return p; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /mapbase/viewmodel_collision.nut: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // github.com/samisalreadytaken 3 | //----------------------------------------------------------------------- 4 | // 5 | // A very basic script that moves the viewmodel when the player is close to a wall, faking viewmodel collisions. 6 | // 7 | // NOTE: Does not work for RPG, and gravity gun right click animation flickers for one frame 8 | // 9 | 10 | if ( SERVER_DLL ) 11 | return; 12 | 13 | // These distances make visual sense, but some may feel too much. 14 | // For example the gravity gun and shotgun are HUGE, but they have lower values to at least be able to see them. 15 | local m_WeaponLength = 16 | { 17 | weapon_crowbar = 32.0, 18 | weapon_pistol = 32.0, 19 | weapon_357 = 32.0, 20 | weapon_smg = 32.0, 21 | weapon_ar2 = 36.0, 22 | weapon_crossbow = 42.0, 23 | weapon_shotgun = 50.0, 24 | weapon_rpg = 0.0, 25 | weapon_physcannon = 64.0, 26 | } 27 | 28 | const kTimeToCollision = 0.15; 29 | const kTimeToNoCollision = 0.2; 30 | 31 | local m_flLastFrac = 0.0; 32 | local m_flStartTime = 0.0; 33 | 34 | // 0: no collision 35 | // 1: in collision 36 | // 2: in transition to collision 37 | // 3: in transition to no collision 38 | local m_nState = 0; 39 | 40 | local Time = Time, 41 | Entities = Entities, 42 | RemapVal = RemapVal, 43 | TraceLineComplex = TraceLineComplex, 44 | MainViewOrigin = MainViewOrigin, 45 | MainViewForward = MainViewForward, 46 | MainViewRight = MainViewRight, 47 | MainViewUp = MainViewUp; 48 | 49 | local function Think(_) 50 | { 51 | local weapon = player.GetActiveWeapon(); 52 | if ( weapon ) 53 | { 54 | local flDist = 32.0; 55 | local weaponclass = weapon.GetClassname(); 56 | 57 | if ( weaponclass in m_WeaponLength ) 58 | flDist = m_WeaponLength[ weaponclass ]; 59 | 60 | if ( flDist ) 61 | { 62 | local vm = Entities.FindByClassname( null, "viewmodel" ); 63 | if ( vm ) 64 | { 65 | //local side = 0.25; 66 | //if ( !Convars.GetInt("cl_righthand") ) 67 | // side = -0.25; 68 | 69 | local viewOrigin = MainViewOrigin(); 70 | local rayDelta = 71 | MainViewForward() 72 | .Add( MainViewRight().Multiply(0.25) ) 73 | .Subtract( MainViewUp().Multiply(0.25) ) 74 | .Multiply( flDist ); 75 | local tr = TraceLineComplex( viewOrigin, rayDelta.Add( viewOrigin ), player, MASK_SHOT_HULL, COLLISION_GROUP_NONE ); 76 | local frac = tr.Fraction(); 77 | tr.Destroy(); 78 | 79 | if ( frac != 1.0 ) 80 | { 81 | m_flLastFrac = frac; 82 | 83 | switch ( m_nState ) 84 | { 85 | case 0: 86 | case 3: 87 | { 88 | m_nState = 2; 89 | m_flStartTime = Time(); 90 | } 91 | } 92 | } 93 | else 94 | { 95 | switch ( m_nState ) 96 | { 97 | case 1: 98 | case 2: 99 | { 100 | m_nState = 3; 101 | m_flStartTime = Time(); 102 | } 103 | } 104 | } 105 | 106 | // NOTE: Transition to transition does not lerp from the last real position, 107 | // but that's fine because transition times are quick. 108 | switch ( m_nState ) 109 | { 110 | // in collision 111 | case 1: 112 | { 113 | local vecDelta = vm.GetForwardVector().Multiply( flDist * ( m_flLastFrac - 1.0 ) ); 114 | vm.SetLocalOrigin( vecDelta.Add( vm.GetLocalOrigin() ) ); 115 | 116 | break; 117 | } 118 | // in transition to collision 119 | case 2: 120 | { 121 | local t = (Time() - m_flStartTime) / kTimeToCollision; 122 | if ( t < 1.0 ) 123 | { 124 | t = RemapVal( t, 0.0, 1.0, 1.0, m_flLastFrac ); 125 | } 126 | else 127 | { 128 | m_nState = 1; 129 | t = m_flLastFrac; 130 | } 131 | 132 | local vecDelta = vm.GetForwardVector().Multiply( flDist * ( t - 1.0 ) ); 133 | vm.SetLocalOrigin( vecDelta.Add( vm.GetLocalOrigin() ) ); 134 | 135 | break; 136 | } 137 | // in transition to no collision 138 | case 3: 139 | { 140 | local t = (Time() - m_flStartTime) / kTimeToNoCollision; 141 | if ( t < 1.0 ) 142 | { 143 | t = RemapVal( t, 0.0, 1.0, m_flLastFrac, 1.0 ); 144 | 145 | local vecDelta = vm.GetForwardVector().Multiply( flDist * ( t - 1.0 ) ); 146 | vm.SetLocalOrigin( vecDelta.Add( vm.GetLocalOrigin() ) ); 147 | } 148 | else 149 | { 150 | m_nState = 0; 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | return 0.0; 159 | } 160 | 161 | 162 | local Init = function(...) 163 | { 164 | Convars.RegisterConvar( "viewmodel_collision", "1", "", FCVAR_CLIENTDLL ); 165 | Convars.SetChangeCallback( "viewmodel_collision", function(...) 166 | { 167 | switch ( Convars.GetInt("viewmodel_collision") ) 168 | { 169 | case 0: 170 | return Entities.First().SetContextThink( "ViewModelCollision", null, 0.0 ); 171 | case 1: 172 | return Entities.First().SetContextThink( "ViewModelCollision", Think, 0.25 ); 173 | } 174 | } ); 175 | 176 | return Entities.First().SetContextThink( "ViewModelCollision_", function(_) 177 | { 178 | return StopListeningToAllGameEvents( "ViewModelCollision" ); 179 | }, 0.1 ); 180 | } 181 | 182 | ListenToGameEvent( "player_spawn", Init, "ViewModelCollision" ); 183 | Hooks.Add( this, "OnRestore", Init, "ViewModelCollision" ); 184 | --------------------------------------------------------------------------------