From eaf6f1ae417551834949a6a52d577dc1cf2d3bae Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 26 Jul 2016 07:22:47 +0700 Subject: [PATCH] Added gradle Refactoring --- .gitignore | 9 +- LICENSE | 674 +++ bin/metamod.dll | Bin 210944 -> 0 bytes bin/metamod.so | Bin 224472 -> 0 bytes build.gradle | 54 + buildSrc/build.gradle | 23 + .../groovy/gradlecpp/VelocityUtils.groovy | 38 + .../src/main/groovy/versioning/GitInfo.groovy | 16 + .../groovy/versioning/GitVersioner.groovy | 129 + .../versioning/MetamodVersionInfo.groovy | 42 + gradle.properties | 3 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52279 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 + gradlew.bat | 90 + lib/libacof32.lib | Bin 53338 -> 0 bytes lib/libirc.a | Bin 543958 -> 0 bytes lib/libirc.lib | Bin 373204 -> 0 bytes lib/linux32/libaelf32.a | Bin 69278 -> 0 bytes metamod/build.gradle | 184 + metamod/include/common/IGameServerData.h | 15 + {sdk => metamod/include}/common/Sequence.h | 0 metamod/include/common/SteamCommon.h | 703 +++ {sdk => metamod/include}/common/beamdef.h | 2 - {sdk => metamod/include}/common/cl_entity.h | 2 - metamod/include/common/com_model.h | 340 ++ {sdk => metamod/include}/common/con_nprint.h | 8 +- {sdk => metamod/include}/common/const.h | 225 +- metamod/include/common/crc.h | 55 + metamod/include/common/cvardef.h | 39 + {sdk => metamod/include}/common/demo_api.h | 2 - .../include}/common/director_cmds.h | 0 {sdk => metamod/include}/common/dlight.h | 2 - {sdk => metamod/include}/common/dll_state.h | 4 +- .../include}/common/entity_state.h | 50 +- .../include}/common/entity_types.h | 0 {sdk => metamod/include}/common/enums.h | 12 +- {sdk => metamod/include}/common/event_api.h | 2 - {sdk => metamod/include}/common/event_args.h | 2 - {sdk => metamod/include}/common/event_flags.h | 2 - {sdk => metamod/include}/common/hltv.h | 0 {sdk => metamod/include}/common/in_buttons.h | 2 - {sdk => metamod/include}/common/ivoicetweak.h | 6 +- metamod/include/common/kbutton.h | 44 + metamod/include/common/mathlib.h | 127 + {sdk => metamod/include}/common/net_api.h | 2 - {sdk => metamod/include}/common/netadr.h | 2 - {sdk => metamod/include}/common/nowin.h | 0 {sdk => metamod/include}/common/parsemsg.cpp | 15 +- {sdk => metamod/include}/common/parsemsg.h | 0 {sdk => metamod/include}/common/particledef.h | 2 - {sdk => metamod/include}/common/pmtrace.h | 2 - metamod/include/common/port.h | 119 + {sdk => metamod/include}/common/qfont.h | 6 +- metamod/include/common/qlimits.h | 39 + metamod/include/common/quakedef.h | 44 + {sdk => metamod/include}/common/r_efx.h | 4 +- {sdk => metamod/include}/common/r_studioint.h | 22 +- {sdk => metamod/include}/common/ref_params.h | 0 {sdk => metamod/include}/common/screenfade.h | 2 - .../include}/common/studio_event.h | 2 - {sdk => metamod/include}/common/triangleapi.h | 2 - {sdk => metamod/include}/common/usercmd.h | 2 - metamod/include/common/vmodes.h | 35 + {sdk => metamod/include}/common/weaponinfo.h | 9 +- metamod/include/common/winsani_in.h | 7 + metamod/include/common/winsani_out.h | 4 + metamod/include/dlls/activity.h | 145 + metamod/include/dlls/activitymap.h | 111 + metamod/include/dlls/airtank.h | 42 + metamod/include/dlls/ammo.h | 98 + metamod/include/dlls/basemonster.h | 105 + metamod/include/dlls/bmodels.h | 131 + metamod/include/dlls/bot/cs_bot.h | 641 +++ metamod/include/dlls/bot/cs_bot_chatter.h | 337 ++ metamod/include/dlls/bot/cs_bot_manager.h | 145 + metamod/include/dlls/bot/cs_gamestate.h | 90 + metamod/include/dlls/buttons.h | 104 + metamod/include/dlls/cbase.h | 375 ++ metamod/include/dlls/cdll_dll.h | 126 + metamod/include/dlls/client.h | 97 + metamod/include/dlls/csbot_dll.h | 50 + metamod/include/dlls/decals.h | 83 + metamod/include/dlls/doors.h | 92 + metamod/include/dlls/effects.h | 407 ++ metamod/include/dlls/enginecallback.h | 178 + metamod/include/dlls/explode.h | 55 + metamod/include/dlls/extdef.h | 102 + metamod/include/dlls/extdll.h | 82 + metamod/include/dlls/func_break.h | 119 + metamod/include/dlls/func_tank.h | 159 + metamod/include/dlls/gamerules.h | 678 +++ metamod/include/dlls/h_battery.h | 45 + metamod/include/dlls/h_cycler.h | 104 + metamod/include/dlls/healthkit.h | 52 + metamod/include/dlls/hintmessage.h | 81 + metamod/include/dlls/hookchains.h | 110 + metamod/include/dlls/hostage/hostage.h | 232 + metamod/include/dlls/hostage/hostage_improv.h | 331 ++ .../include/dlls/hostage/hostage_localnav.h | 58 + metamod/include/dlls/hostage/hostage_states.h | 203 + metamod/include/dlls/items.h | 155 + metamod/include/dlls/lights.h | 50 + metamod/include/dlls/mapinfo.h | 40 + metamod/include/dlls/maprules.h | 236 + metamod/include/dlls/monsterevent.h | 44 + metamod/include/dlls/monsters.h | 113 + metamod/include/dlls/mortar.h | 55 + metamod/include/dlls/observer.h | 32 + metamod/include/dlls/pathcorner.h | 39 + metamod/include/dlls/plats.h | 178 + metamod/include/dlls/player.h | 578 ++ metamod/include/dlls/regamedll_api.h | 413 ++ metamod/include/dlls/regamedll_common.h | 95 + metamod/include/dlls/regamedll_const.h | 104 + metamod/include/dlls/regamedll_interfaces.h | 296 + metamod/include/dlls/revert_saved.h | 49 + metamod/include/dlls/skill.h | 53 + metamod/include/dlls/sound.h | 141 + metamod/include/dlls/spectator.h | 33 + metamod/include/dlls/subs.h | 40 + metamod/include/dlls/training_gamerules.h | 84 + metamod/include/dlls/trains.h | 149 + metamod/include/dlls/triggers.h | 358 ++ metamod/include/dlls/unisignals.h | 57 + metamod/include/dlls/util.h | 182 + metamod/include/dlls/vector.h | 176 + metamod/include/dlls/vehicle.h | 53 + metamod/include/dlls/weapons.h | 894 +++ metamod/include/dlls/weapontype.h | 412 ++ metamod/include/dlls/wpn_shared.h | 598 ++ metamod/include/engine/FlightRecorder.h | 61 + metamod/include/engine/Sequence.h | 201 + metamod/include/engine/archtypes.h | 66 + metamod/include/engine/bspfile.h | 169 + metamod/include/engine/cmd_rehlds.h | 50 + metamod/include/engine/common_rehlds.h | 73 + metamod/include/engine/crc32c.cpp | 143 + metamod/include/engine/crc32c.h | 22 + {sdk => metamod/include}/engine/custom.h | 23 +- .../include}/engine/customentity.h | 0 metamod/include/engine/d_local.h | 46 + {sdk => metamod/include}/engine/edict.h | 2 - {sdk => metamod/include}/engine/eiface.h | 99 +- metamod/include/engine/keydefs.h | 131 + metamod/include/engine/maintypes.h | 52 + metamod/include/engine/model.h | 415 ++ metamod/include/engine/modelgen.h | 144 + metamod/include/engine/osconfig.h | 194 + {sdk => metamod/include}/engine/progdefs.h | 8 +- {sdk => metamod/include}/engine/progs.h | 0 metamod/include/engine/rehlds_api.h | 299 + metamod/include/engine/rehlds_interfaces.h | 132 + {sdk => metamod/include}/engine/shake.h | 1 + metamod/include/engine/spritegn.h | 90 + metamod/include/engine/static_map.h | 257 + {sdk => metamod/include}/engine/studio.h | 40 +- metamod/include/engine/sys_shared.cpp | 72 + metamod/include/engine/sys_shared.h | 39 + metamod/include/engine/userid_rehlds.h | 47 + metamod/include/game_shared/GameEvent.h | 138 + metamod/include/game_shared/bitvec.h | 157 + metamod/include/game_shared/bot/bot.h | 164 + .../include/game_shared/bot/bot_constants.h | 47 + metamod/include/game_shared/bot/bot_manager.h | 70 + metamod/include/game_shared/bot/bot_profile.h | 116 + metamod/include/game_shared/bot/bot_util.h | 141 + metamod/include/game_shared/bot/improv.h | 120 + metamod/include/game_shared/bot/nav.h | 400 ++ metamod/include/game_shared/bot/nav_area.h | 320 ++ metamod/include/game_shared/bot/nav_node.h | 110 + metamod/include/game_shared/bot/nav_path.h | 99 + .../game_shared/bot/simple_state_machine.h | 101 + metamod/include/game_shared/perf_counter.h | 183 + metamod/include/game_shared/shared_util.h | 63 + metamod/include/game_shared/simple_checksum.h | 49 + metamod/include/game_shared/steam_util.h | 76 + metamod/include/game_shared/voice_common.h | 36 + metamod/include/game_shared/voice_gamemgr.h | 56 + metamod/include/pm_shared/pm_defs.h | 192 + metamod/include/pm_shared/pm_info.h | 30 + metamod/include/pm_shared/pm_materials.h | 45 + metamod/include/pm_shared/pm_movevars.h | 59 + metamod/include/pm_shared/pm_shared.h | 75 + metamod/include/public/FileSystem.h | 189 + metamod/include/public/basetypes.h | 287 + metamod/include/public/commonmacros.h | 30 + metamod/include/public/interface.cpp | 263 + .../include/public}/interface.h | 67 +- metamod/include/public/protected_things.h | 187 + metamod/include/public/tier0/dbg.cpp | 444 ++ metamod/include/public/tier0/dbg.h | 451 ++ metamod/include/public/tier0/platform.h | 630 +++ metamod/include/public/utlmemory.h | 357 ++ metamod/include/public/utlvector.h | 565 ++ metamod/msvc/PostBuild.bat | 39 + metamod/msvc/PreBuild.bat | 241 + {msvc => metamod/msvc}/metamod.def | 2 +- metamod/msvc/metamod.rc | 108 + metamod/msvc/metamod.vcxproj | 273 + .../msvc}/metamod.vcxproj.filters | 229 +- metamod/msvc/reapi.rc | 108 + metamod/msvc/resource.h | 14 + metamod/msvc/test.bat | 65 + {src => metamod/src}/api_hook.cpp | 370 +- {src => metamod/src}/api_hook.h | 8 +- {src => metamod/src}/api_info.cpp | 4 +- {src => metamod/src}/api_info.h | 64 +- {src => metamod/src}/commands_meta.cpp | 356 +- metamod/src/commands_meta.h | 44 + {src => metamod/src}/comp_dep.h | 3 - metamod/src/conf_meta.cpp | 192 + metamod/src/conf_meta.h | 54 + {src => metamod/src}/dllapi.cpp | 87 +- {src => metamod/src}/dllapi.h | 2 +- {src => metamod/src}/engine_api.cpp | 342 +- metamod/src/engine_api.h | 180 + metamod/src/engine_t.h | 37 + {src => metamod/src}/enginecallbacks.h | 20 +- metamod/src/game_support.cpp | 146 + {src => metamod/src}/game_support.h | 15 +- {src => metamod/src}/h_export.cpp | 35 +- {src => metamod/src}/h_export.h | 5 +- {src => metamod/src}/linkent.h | 25 +- {src => metamod/src}/linkplug.cpp | 3 +- {src => metamod/src}/log_meta.cpp | 115 +- {src => metamod/src}/log_meta.h | 44 +- {src => metamod/src}/meta_api.h | 14 +- {src => metamod/src}/meta_eiface.cpp | 381 +- metamod/src/meta_eiface.h | 302 + {src => metamod/src}/metamod.cpp | 217 +- {src => metamod/src}/metamod.h | 62 +- {src => metamod/src}/mhook.cpp | 0 {src => metamod/src}/mlist.cpp | 950 ++-- metamod/src/mlist.h | 50 + metamod/src/mm_pextensions.h | 80 + {src => metamod/src}/mplayer.cpp | 77 +- metamod/src/mplayer.h | 38 + {src => metamod/src}/mplugin.cpp | 1072 ++-- metamod/src/mplugin.h | 184 + {src => metamod/src}/mreg.cpp | 346 +- metamod/src/mreg.h | 137 + {src => metamod/src}/mutil.cpp | 243 +- {src => metamod/src}/mutil.h | 2 +- metamod/src/new_baseclass.h | 38 + {src => metamod/src}/osdep.cpp | 215 +- {src => metamod/src}/osdep.h | 231 +- .../src}/osdep_detect_gamedll_linux.cpp | 215 +- .../src}/osdep_detect_gamedll_win32.cpp | 158 +- {src => metamod/src}/osdep_linkent_linux.cpp | 162 +- metamod/src/osdep_linkent_win32.cpp | 191 + metamod/src/osdep_p.cpp | 84 + metamod/src/osdep_p.h | 33 + {src => metamod/src}/plinfo.h | 3 +- metamod/src/precompiled.cpp | 1 + metamod/src/precompiled.h | 59 + {src => metamod/src}/reg_support.cpp | 89 +- metamod/src/reg_support.h | 10 + {src => metamod/src}/ret_type.h | 24 +- metamod/src/sdk_util.cpp | 77 + {src => metamod/src}/sdk_util.h | 47 +- {src => metamod/src}/support_meta.cpp | 75 +- {src => metamod/src}/support_meta.h | 78 +- {src => metamod/src}/types_meta.h | 17 +- metamod/version/appversion.vm | 27 + metamod/version/version.cpp | 10 + msvc/metamod.sln | 2 +- msvc/metamod.vcxproj | 166 - msvc/res_meta.rc | 76 - publish.gradle | 38 + sdk/common/com_model.h | 362 -- sdk/common/crc.h | 67 - sdk/common/cvardef.h | 37 - sdk/common/interface.cpp | 150 - sdk/common/mathlib.h | 158 - sdk/common/port.h | 122 - sdk/dlls/AI_BaseNPC_Schedule.cpp | 1514 ----- sdk/dlls/Makefile | 187 - sdk/dlls/Wxdebug.cpp | 395 -- sdk/dlls/activity.h | 109 - sdk/dlls/activitymap.h | 97 - sdk/dlls/aflock.cpp | 911 --- sdk/dlls/agrunt.cpp | 1188 ---- sdk/dlls/airtank.cpp | 118 - sdk/dlls/animating.cpp | 318 -- sdk/dlls/animation.cpp | 535 -- sdk/dlls/animation.h | 47 - sdk/dlls/apache.cpp | 1049 ---- sdk/dlls/barnacle.cpp | 428 -- sdk/dlls/barney.cpp | 843 --- sdk/dlls/basemonster.h | 339 -- sdk/dlls/bigmomma.cpp | 1250 ----- sdk/dlls/bloater.cpp | 219 - sdk/dlls/bmodels.cpp | 958 ---- sdk/dlls/bullsquid.cpp | 1279 ----- sdk/dlls/buttons.cpp | 1284 ----- sdk/dlls/cbase.cpp | 771 --- sdk/dlls/cbase.h | 802 --- sdk/dlls/cdll_dll.h | 46 - sdk/dlls/client.cpp | 1915 ------- sdk/dlls/client.h | 65 - sdk/dlls/combat.cpp | 1701 ------ sdk/dlls/controller.cpp | 1428 ----- sdk/dlls/crossbow.cpp | 547 -- sdk/dlls/crowbar.cpp | 318 -- sdk/dlls/decals.h | 75 - sdk/dlls/defaultai.cpp | 1232 ----- sdk/dlls/defaultai.h | 98 - sdk/dlls/doors.cpp | 1052 ---- sdk/dlls/doors.h | 33 - sdk/dlls/effects.cpp | 2268 -------- sdk/dlls/effects.h | 209 - sdk/dlls/egon.cpp | 568 -- sdk/dlls/enginecallback.h | 165 - sdk/dlls/explode.cpp | 273 - sdk/dlls/explode.h | 32 - sdk/dlls/extdll.h | 111 - sdk/dlls/flyingmonster.cpp | 281 - sdk/dlls/flyingmonster.h | 53 - sdk/dlls/func_break.cpp | 1010 ---- sdk/dlls/func_break.h | 74 - sdk/dlls/func_tank.cpp | 1034 ---- sdk/dlls/game.cpp | 890 --- sdk/dlls/game.h | 45 - sdk/dlls/gamerules.cpp | 347 -- sdk/dlls/gamerules.h | 360 -- sdk/dlls/gargantua.cpp | 1367 ----- sdk/dlls/gauss.cpp | 623 --- sdk/dlls/genericmonster.cpp | 140 - sdk/dlls/ggrenade.cpp | 488 -- sdk/dlls/globals.cpp | 39 - sdk/dlls/glock.cpp | 325 -- sdk/dlls/gman.cpp | 237 - sdk/dlls/h_ai.cpp | 199 - sdk/dlls/h_battery.cpp | 200 - sdk/dlls/h_cine.cpp | 241 - sdk/dlls/h_cycler.cpp | 471 -- sdk/dlls/h_export.cpp | 63 - sdk/dlls/handgrenade.cpp | 233 - sdk/dlls/hassassin.cpp | 1017 ---- sdk/dlls/headcrab.cpp | 555 -- sdk/dlls/healthkit.cpp | 264 - sdk/dlls/hgrunt.cpp | 2518 --------- sdk/dlls/hl.def | 5 - sdk/dlls/hl.dsp | 1637 ------ sdk/dlls/hlgl.def | 15 - sdk/dlls/hornet.cpp | 419 -- sdk/dlls/hornet.h | 58 - sdk/dlls/hornetgun.cpp | 305 - sdk/dlls/houndeye.cpp | 1308 ----- sdk/dlls/ichthyosaur.cpp | 1108 ---- sdk/dlls/islave.cpp | 864 --- sdk/dlls/items.cpp | 342 -- sdk/dlls/items.h | 29 - sdk/dlls/leech.cpp | 723 --- sdk/dlls/lights.cpp | 199 - sdk/dlls/maprules.cpp | 918 ---- sdk/dlls/maprules.h | 22 - sdk/dlls/monsterevent.h | 34 - sdk/dlls/monstermaker.cpp | 292 - sdk/dlls/monsters.cpp | 3448 ------------ sdk/dlls/monsters.h | 183 - sdk/dlls/monsterstate.cpp | 239 - sdk/dlls/mortar.cpp | 323 -- sdk/dlls/mp5.cpp | 385 -- sdk/dlls/mpstubb.cpp | 264 - sdk/dlls/msvc10/hl.sln | 20 - sdk/dlls/msvc10/hl.vcxproj | 509 -- sdk/dlls/msvc10/hl.vcxproj.filters | 154 - sdk/dlls/msvc11/hl.sln | 20 - sdk/dlls/msvc11/hl.vcxproj | 512 -- sdk/dlls/msvc11/hl.vcxproj.filters | 154 - sdk/dlls/multiplay_gamerules.cpp | 1692 ------ sdk/dlls/nihilanth.cpp | 1850 ------- sdk/dlls/nodes.cpp | 3657 ------------ sdk/dlls/nodes.h | 379 -- sdk/dlls/observer.cpp | 280 - sdk/dlls/osprey.cpp | 805 --- sdk/dlls/pathcorner.cpp | 428 -- sdk/dlls/plane.cpp | 60 - sdk/dlls/plane.h | 43 - sdk/dlls/plats.cpp | 2285 -------- sdk/dlls/player.cpp | 4881 ----------------- sdk/dlls/player.h | 337 -- sdk/dlls/playermonster.cpp | 122 - sdk/dlls/python.cpp | 309 -- sdk/dlls/rat.cpp | 98 - sdk/dlls/roach.cpp | 460 -- sdk/dlls/rpg.cpp | 617 --- sdk/dlls/satchel.cpp | 490 -- sdk/dlls/saverestore.h | 176 - sdk/dlls/schedule.cpp | 1514 ----- sdk/dlls/schedule.h | 290 - sdk/dlls/scientist.cpp | 1435 ----- sdk/dlls/scripted.cpp | 1260 ----- sdk/dlls/scripted.h | 107 - sdk/dlls/scriptevent.h | 29 - sdk/dlls/shotgun.cpp | 401 -- sdk/dlls/singleplay_gamerules.cpp | 328 -- sdk/dlls/skill.cpp | 46 - sdk/dlls/skill.h | 147 - sdk/dlls/sound.cpp | 1982 ------- sdk/dlls/soundent.cpp | 379 -- sdk/dlls/soundent.h | 95 - sdk/dlls/spectator.cpp | 149 - sdk/dlls/spectator.h | 27 - sdk/dlls/squad.h | 20 - sdk/dlls/squadmonster.cpp | 623 --- sdk/dlls/squadmonster.h | 120 - sdk/dlls/squeakgrenade.cpp | 600 -- sdk/dlls/stats.cpp | 156 - sdk/dlls/subs.cpp | 567 -- sdk/dlls/talkmonster.cpp | 1467 ----- sdk/dlls/talkmonster.h | 183 - sdk/dlls/teamplay_gamerules.cpp | 627 --- sdk/dlls/teamplay_gamerules.h | 57 - sdk/dlls/tempmonster.cpp | 117 - sdk/dlls/tentacle.cpp | 1046 ---- sdk/dlls/trains.h | 127 - sdk/dlls/triggers.cpp | 2429 -------- sdk/dlls/tripmine.cpp | 526 -- sdk/dlls/turret.cpp | 1303 ----- sdk/dlls/util.cpp | 2551 --------- sdk/dlls/util.h | 548 -- sdk/dlls/vector.h | 111 - sdk/dlls/weapons.cpp | 1617 ------ sdk/dlls/weapons.h | 1021 ---- sdk/dlls/world.cpp | 742 --- sdk/dlls/wpn_shared/hl_wpn_glock.cpp | 274 - sdk/dlls/wxdebug.h | 137 - sdk/dlls/xen.cpp | 584 -- sdk/dlls/zombie.cpp | 344 -- sdk/engine/APIProxy.h | 939 ---- sdk/engine/anorms.h | 177 - sdk/engine/archtypes.h | 41 - sdk/engine/cdll_int.h | 467 -- sdk/pm_shared/pm_debug.c | 322 -- sdk/pm_shared/pm_debug.h | 28 - sdk/pm_shared/pm_defs.h | 267 - sdk/pm_shared/pm_info.h | 26 - sdk/pm_shared/pm_materials.h | 38 - sdk/pm_shared/pm_math.c | 435 -- sdk/pm_shared/pm_movevars.h | 47 - sdk/pm_shared/pm_shared.c | 3343 ----------- sdk/pm_shared/pm_shared.h | 40 - settings.gradle | 2 + shared.gradle | 33 + shared_icc.gradle | 66 + shared_msvc.gradle | 125 + src/asmlib.h | 224 - src/commands_meta.h | 47 - src/conf_meta.cpp | 202 - src/conf_meta.h | 62 - src/engine_api.h | 204 - src/engine_t.h | 82 - src/engineinfo.cpp | 379 -- src/engineinfo.h | 245 - src/game_autodetect.cpp | 89 - src/game_autodetect.h | 7 - src/game_support.cpp | 294 - src/games.h | 99 - src/info_name.h | 20 - src/meta_eiface.h | 437 -- src/mlist.h | 52 - src/mm_pextensions.h | 85 - src/mplayer.h | 47 - src/mplugin.h | 195 - src/mreg.h | 155 - src/new_baseclass.h | 42 - src/osdep_linkent_win32.cpp | 213 - src/osdep_p.cpp | 92 - src/osdep_p.h | 45 - src/reg_support.h | 13 - src/sdk_util.cpp | 76 - src/tqueue.h | 114 - src/vdate.cpp | 22 - src/vdate.h | 9 - src/vers_meta.h | 26 - 478 files changed, 29804 insertions(+), 114035 deletions(-) create mode 100644 LICENSE delete mode 100644 bin/metamod.dll delete mode 100644 bin/metamod.so create mode 100644 build.gradle create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/gradlecpp/VelocityUtils.groovy create mode 100644 buildSrc/src/main/groovy/versioning/GitInfo.groovy create mode 100644 buildSrc/src/main/groovy/versioning/GitVersioner.groovy create mode 100644 buildSrc/src/main/groovy/versioning/MetamodVersionInfo.groovy create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat delete mode 100644 lib/libacof32.lib delete mode 100644 lib/libirc.a delete mode 100644 lib/libirc.lib delete mode 100644 lib/linux32/libaelf32.a create mode 100644 metamod/build.gradle create mode 100644 metamod/include/common/IGameServerData.h rename {sdk => metamod/include}/common/Sequence.h (100%) create mode 100644 metamod/include/common/SteamCommon.h rename {sdk => metamod/include}/common/beamdef.h (97%) rename {sdk => metamod/include}/common/cl_entity.h (98%) create mode 100644 metamod/include/common/com_model.h rename {sdk => metamod/include}/common/con_nprint.h (84%) rename {sdk => metamod/include}/common/const.h (79%) create mode 100644 metamod/include/common/crc.h create mode 100644 metamod/include/common/cvardef.h rename {sdk => metamod/include}/common/demo_api.h (94%) rename {sdk => metamod/include}/common/director_cmds.h (100%) rename {sdk => metamod/include}/common/dlight.h (94%) rename {sdk => metamod/include}/common/dll_state.h (79%) rename {sdk => metamod/include}/common/entity_state.h (85%) rename {sdk => metamod/include}/common/entity_types.h (100%) rename {sdk => metamod/include}/common/enums.h (89%) rename {sdk => metamod/include}/common/event_api.h (97%) rename {sdk => metamod/include}/common/event_args.h (95%) rename {sdk => metamod/include}/common/event_flags.h (97%) rename {sdk => metamod/include}/common/hltv.h (100%) rename {sdk => metamod/include}/common/in_buttons.h (95%) rename {sdk => metamod/include}/common/ivoicetweak.h (91%) create mode 100644 metamod/include/common/kbutton.h create mode 100644 metamod/include/common/mathlib.h rename {sdk => metamod/include}/common/net_api.h (98%) rename {sdk => metamod/include}/common/netadr.h (94%) rename {sdk => metamod/include}/common/nowin.h (100%) rename {sdk => metamod/include}/common/parsemsg.cpp (94%) rename {sdk => metamod/include}/common/parsemsg.h (100%) rename {sdk => metamod/include}/common/particledef.h (96%) rename {sdk => metamod/include}/common/pmtrace.h (96%) create mode 100644 metamod/include/common/port.h rename {sdk => metamod/include}/common/qfont.h (90%) create mode 100644 metamod/include/common/qlimits.h create mode 100644 metamod/include/common/quakedef.h rename {sdk => metamod/include}/common/r_efx.h (98%) rename {sdk => metamod/include}/common/r_studioint.h (92%) rename {sdk => metamod/include}/common/ref_params.h (100%) rename {sdk => metamod/include}/common/screenfade.h (93%) rename {sdk => metamod/include}/common/studio_event.h (93%) rename {sdk => metamod/include}/common/triangleapi.h (97%) rename {sdk => metamod/include}/common/usercmd.h (96%) create mode 100644 metamod/include/common/vmodes.h rename {sdk => metamod/include}/common/weaponinfo.h (91%) create mode 100644 metamod/include/common/winsani_in.h create mode 100644 metamod/include/common/winsani_out.h create mode 100644 metamod/include/dlls/activity.h create mode 100644 metamod/include/dlls/activitymap.h create mode 100644 metamod/include/dlls/airtank.h create mode 100644 metamod/include/dlls/ammo.h create mode 100644 metamod/include/dlls/basemonster.h create mode 100644 metamod/include/dlls/bmodels.h create mode 100644 metamod/include/dlls/bot/cs_bot.h create mode 100644 metamod/include/dlls/bot/cs_bot_chatter.h create mode 100644 metamod/include/dlls/bot/cs_bot_manager.h create mode 100644 metamod/include/dlls/bot/cs_gamestate.h create mode 100644 metamod/include/dlls/buttons.h create mode 100644 metamod/include/dlls/cbase.h create mode 100644 metamod/include/dlls/cdll_dll.h create mode 100644 metamod/include/dlls/client.h create mode 100644 metamod/include/dlls/csbot_dll.h create mode 100644 metamod/include/dlls/decals.h create mode 100644 metamod/include/dlls/doors.h create mode 100644 metamod/include/dlls/effects.h create mode 100644 metamod/include/dlls/enginecallback.h create mode 100644 metamod/include/dlls/explode.h create mode 100644 metamod/include/dlls/extdef.h create mode 100644 metamod/include/dlls/extdll.h create mode 100644 metamod/include/dlls/func_break.h create mode 100644 metamod/include/dlls/func_tank.h create mode 100644 metamod/include/dlls/gamerules.h create mode 100644 metamod/include/dlls/h_battery.h create mode 100644 metamod/include/dlls/h_cycler.h create mode 100644 metamod/include/dlls/healthkit.h create mode 100644 metamod/include/dlls/hintmessage.h create mode 100644 metamod/include/dlls/hookchains.h create mode 100644 metamod/include/dlls/hostage/hostage.h create mode 100644 metamod/include/dlls/hostage/hostage_improv.h create mode 100644 metamod/include/dlls/hostage/hostage_localnav.h create mode 100644 metamod/include/dlls/hostage/hostage_states.h create mode 100644 metamod/include/dlls/items.h create mode 100644 metamod/include/dlls/lights.h create mode 100644 metamod/include/dlls/mapinfo.h create mode 100644 metamod/include/dlls/maprules.h create mode 100644 metamod/include/dlls/monsterevent.h create mode 100644 metamod/include/dlls/monsters.h create mode 100644 metamod/include/dlls/mortar.h create mode 100644 metamod/include/dlls/observer.h create mode 100644 metamod/include/dlls/pathcorner.h create mode 100644 metamod/include/dlls/plats.h create mode 100644 metamod/include/dlls/player.h create mode 100644 metamod/include/dlls/regamedll_api.h create mode 100644 metamod/include/dlls/regamedll_common.h create mode 100644 metamod/include/dlls/regamedll_const.h create mode 100644 metamod/include/dlls/regamedll_interfaces.h create mode 100644 metamod/include/dlls/revert_saved.h create mode 100644 metamod/include/dlls/skill.h create mode 100644 metamod/include/dlls/sound.h create mode 100644 metamod/include/dlls/spectator.h create mode 100644 metamod/include/dlls/subs.h create mode 100644 metamod/include/dlls/training_gamerules.h create mode 100644 metamod/include/dlls/trains.h create mode 100644 metamod/include/dlls/triggers.h create mode 100644 metamod/include/dlls/unisignals.h create mode 100644 metamod/include/dlls/util.h create mode 100644 metamod/include/dlls/vector.h create mode 100644 metamod/include/dlls/vehicle.h create mode 100644 metamod/include/dlls/weapons.h create mode 100644 metamod/include/dlls/weapontype.h create mode 100644 metamod/include/dlls/wpn_shared.h create mode 100644 metamod/include/engine/FlightRecorder.h create mode 100644 metamod/include/engine/Sequence.h create mode 100644 metamod/include/engine/archtypes.h create mode 100644 metamod/include/engine/bspfile.h create mode 100644 metamod/include/engine/cmd_rehlds.h create mode 100644 metamod/include/engine/common_rehlds.h create mode 100644 metamod/include/engine/crc32c.cpp create mode 100644 metamod/include/engine/crc32c.h rename {sdk => metamod/include}/engine/custom.h (85%) rename {sdk => metamod/include}/engine/customentity.h (100%) create mode 100644 metamod/include/engine/d_local.h rename {sdk => metamod/include}/engine/edict.h (94%) rename {sdk => metamod/include}/engine/eiface.h (91%) create mode 100644 metamod/include/engine/keydefs.h create mode 100644 metamod/include/engine/maintypes.h create mode 100644 metamod/include/engine/model.h create mode 100644 metamod/include/engine/modelgen.h create mode 100644 metamod/include/engine/osconfig.h rename {sdk => metamod/include}/engine/progdefs.h (97%) rename {sdk => metamod/include}/engine/progs.h (100%) create mode 100644 metamod/include/engine/rehlds_api.h create mode 100644 metamod/include/engine/rehlds_interfaces.h rename {sdk => metamod/include}/engine/shake.h (99%) create mode 100644 metamod/include/engine/spritegn.h create mode 100644 metamod/include/engine/static_map.h rename {sdk => metamod/include}/engine/studio.h (93%) create mode 100644 metamod/include/engine/sys_shared.cpp create mode 100644 metamod/include/engine/sys_shared.h create mode 100644 metamod/include/engine/userid_rehlds.h create mode 100644 metamod/include/game_shared/GameEvent.h create mode 100644 metamod/include/game_shared/bitvec.h create mode 100644 metamod/include/game_shared/bot/bot.h create mode 100644 metamod/include/game_shared/bot/bot_constants.h create mode 100644 metamod/include/game_shared/bot/bot_manager.h create mode 100644 metamod/include/game_shared/bot/bot_profile.h create mode 100644 metamod/include/game_shared/bot/bot_util.h create mode 100644 metamod/include/game_shared/bot/improv.h create mode 100644 metamod/include/game_shared/bot/nav.h create mode 100644 metamod/include/game_shared/bot/nav_area.h create mode 100644 metamod/include/game_shared/bot/nav_node.h create mode 100644 metamod/include/game_shared/bot/nav_path.h create mode 100644 metamod/include/game_shared/bot/simple_state_machine.h create mode 100644 metamod/include/game_shared/perf_counter.h create mode 100644 metamod/include/game_shared/shared_util.h create mode 100644 metamod/include/game_shared/simple_checksum.h create mode 100644 metamod/include/game_shared/steam_util.h create mode 100644 metamod/include/game_shared/voice_common.h create mode 100644 metamod/include/game_shared/voice_gamemgr.h create mode 100644 metamod/include/pm_shared/pm_defs.h create mode 100644 metamod/include/pm_shared/pm_info.h create mode 100644 metamod/include/pm_shared/pm_materials.h create mode 100644 metamod/include/pm_shared/pm_movevars.h create mode 100644 metamod/include/pm_shared/pm_shared.h create mode 100644 metamod/include/public/FileSystem.h create mode 100644 metamod/include/public/basetypes.h create mode 100644 metamod/include/public/commonmacros.h create mode 100644 metamod/include/public/interface.cpp rename {sdk/common => metamod/include/public}/interface.h (71%) create mode 100644 metamod/include/public/protected_things.h create mode 100644 metamod/include/public/tier0/dbg.cpp create mode 100644 metamod/include/public/tier0/dbg.h create mode 100644 metamod/include/public/tier0/platform.h create mode 100644 metamod/include/public/utlmemory.h create mode 100644 metamod/include/public/utlvector.h create mode 100644 metamod/msvc/PostBuild.bat create mode 100644 metamod/msvc/PreBuild.bat rename {msvc => metamod/msvc}/metamod.def (75%) create mode 100644 metamod/msvc/metamod.rc create mode 100644 metamod/msvc/metamod.vcxproj rename {msvc => metamod/msvc}/metamod.vcxproj.filters (70%) create mode 100644 metamod/msvc/reapi.rc create mode 100644 metamod/msvc/resource.h create mode 100644 metamod/msvc/test.bat rename {src => metamod/src}/api_hook.cpp (58%) rename {src => metamod/src}/api_hook.h (96%) rename {src => metamod/src}/api_info.cpp (99%) rename {src => metamod/src}/api_info.h (88%) rename {src => metamod/src}/commands_meta.cpp (61%) create mode 100644 metamod/src/commands_meta.h rename {src => metamod/src}/comp_dep.h (94%) create mode 100644 metamod/src/conf_meta.cpp create mode 100644 metamod/src/conf_meta.h rename {src => metamod/src}/dllapi.cpp (91%) rename {src => metamod/src}/dllapi.h (99%) rename {src => metamod/src}/engine_api.cpp (86%) create mode 100644 metamod/src/engine_api.h create mode 100644 metamod/src/engine_t.h rename {src => metamod/src}/enginecallbacks.h (82%) create mode 100644 metamod/src/game_support.cpp rename {src => metamod/src}/game_support.h (52%) rename {src => metamod/src}/h_export.cpp (71%) rename {src => metamod/src}/h_export.h (82%) rename {src => metamod/src}/linkent.h (80%) rename {src => metamod/src}/linkplug.cpp (51%) rename {src => metamod/src}/log_meta.cpp (54%) rename {src => metamod/src}/log_meta.h (67%) rename {src => metamod/src}/meta_api.h (96%) rename {src => metamod/src}/meta_eiface.cpp (56%) create mode 100644 metamod/src/meta_eiface.h rename {src => metamod/src}/metamod.cpp (67%) rename {src => metamod/src}/metamod.h (82%) rename {src => metamod/src}/mhook.cpp (100%) rename {src => metamod/src}/mlist.cpp (53%) create mode 100644 metamod/src/mlist.h create mode 100644 metamod/src/mm_pextensions.h rename {src => metamod/src}/mplayer.cpp (51%) create mode 100644 metamod/src/mplayer.h rename {src => metamod/src}/mplugin.cpp (68%) create mode 100644 metamod/src/mplugin.h rename {src => metamod/src}/mreg.cpp (62%) create mode 100644 metamod/src/mreg.h rename {src => metamod/src}/mutil.cpp (64%) rename {src => metamod/src}/mutil.h (98%) create mode 100644 metamod/src/new_baseclass.h rename {src => metamod/src}/osdep.cpp (72%) rename {src => metamod/src}/osdep.h (57%) rename {src => metamod/src}/osdep_detect_gamedll_linux.cpp (63%) rename {src => metamod/src}/osdep_detect_gamedll_win32.cpp (59%) rename {src => metamod/src}/osdep_linkent_linux.cpp (53%) create mode 100644 metamod/src/osdep_linkent_win32.cpp create mode 100644 metamod/src/osdep_p.cpp create mode 100644 metamod/src/osdep_p.h rename {src => metamod/src}/plinfo.h (97%) create mode 100644 metamod/src/precompiled.cpp create mode 100644 metamod/src/precompiled.h rename {src => metamod/src}/reg_support.cpp (79%) create mode 100644 metamod/src/reg_support.h rename {src => metamod/src}/ret_type.h (72%) create mode 100644 metamod/src/sdk_util.cpp rename {src => metamod/src}/sdk_util.h (52%) rename {src => metamod/src}/support_meta.cpp (59%) rename {src => metamod/src}/support_meta.h (54%) rename {src => metamod/src}/types_meta.h (84%) create mode 100644 metamod/version/appversion.vm create mode 100644 metamod/version/version.cpp delete mode 100644 msvc/metamod.vcxproj delete mode 100644 msvc/res_meta.rc create mode 100644 publish.gradle delete mode 100644 sdk/common/com_model.h delete mode 100644 sdk/common/crc.h delete mode 100644 sdk/common/cvardef.h delete mode 100644 sdk/common/interface.cpp delete mode 100644 sdk/common/mathlib.h delete mode 100644 sdk/common/port.h delete mode 100644 sdk/dlls/AI_BaseNPC_Schedule.cpp delete mode 100644 sdk/dlls/Makefile delete mode 100644 sdk/dlls/Wxdebug.cpp delete mode 100644 sdk/dlls/activity.h delete mode 100644 sdk/dlls/activitymap.h delete mode 100644 sdk/dlls/aflock.cpp delete mode 100644 sdk/dlls/agrunt.cpp delete mode 100644 sdk/dlls/airtank.cpp delete mode 100644 sdk/dlls/animating.cpp delete mode 100644 sdk/dlls/animation.cpp delete mode 100644 sdk/dlls/animation.h delete mode 100644 sdk/dlls/apache.cpp delete mode 100644 sdk/dlls/barnacle.cpp delete mode 100644 sdk/dlls/barney.cpp delete mode 100644 sdk/dlls/basemonster.h delete mode 100644 sdk/dlls/bigmomma.cpp delete mode 100644 sdk/dlls/bloater.cpp delete mode 100644 sdk/dlls/bmodels.cpp delete mode 100644 sdk/dlls/bullsquid.cpp delete mode 100644 sdk/dlls/buttons.cpp delete mode 100644 sdk/dlls/cbase.cpp delete mode 100644 sdk/dlls/cbase.h delete mode 100644 sdk/dlls/cdll_dll.h delete mode 100644 sdk/dlls/client.cpp delete mode 100644 sdk/dlls/client.h delete mode 100644 sdk/dlls/combat.cpp delete mode 100644 sdk/dlls/controller.cpp delete mode 100644 sdk/dlls/crossbow.cpp delete mode 100644 sdk/dlls/crowbar.cpp delete mode 100644 sdk/dlls/decals.h delete mode 100644 sdk/dlls/defaultai.cpp delete mode 100644 sdk/dlls/defaultai.h delete mode 100644 sdk/dlls/doors.cpp delete mode 100644 sdk/dlls/doors.h delete mode 100644 sdk/dlls/effects.cpp delete mode 100644 sdk/dlls/effects.h delete mode 100644 sdk/dlls/egon.cpp delete mode 100644 sdk/dlls/enginecallback.h delete mode 100644 sdk/dlls/explode.cpp delete mode 100644 sdk/dlls/explode.h delete mode 100644 sdk/dlls/extdll.h delete mode 100644 sdk/dlls/flyingmonster.cpp delete mode 100644 sdk/dlls/flyingmonster.h delete mode 100644 sdk/dlls/func_break.cpp delete mode 100644 sdk/dlls/func_break.h delete mode 100644 sdk/dlls/func_tank.cpp delete mode 100644 sdk/dlls/game.cpp delete mode 100644 sdk/dlls/game.h delete mode 100644 sdk/dlls/gamerules.cpp delete mode 100644 sdk/dlls/gamerules.h delete mode 100644 sdk/dlls/gargantua.cpp delete mode 100644 sdk/dlls/gauss.cpp delete mode 100644 sdk/dlls/genericmonster.cpp delete mode 100644 sdk/dlls/ggrenade.cpp delete mode 100644 sdk/dlls/globals.cpp delete mode 100644 sdk/dlls/glock.cpp delete mode 100644 sdk/dlls/gman.cpp delete mode 100644 sdk/dlls/h_ai.cpp delete mode 100644 sdk/dlls/h_battery.cpp delete mode 100644 sdk/dlls/h_cine.cpp delete mode 100644 sdk/dlls/h_cycler.cpp delete mode 100644 sdk/dlls/h_export.cpp delete mode 100644 sdk/dlls/handgrenade.cpp delete mode 100644 sdk/dlls/hassassin.cpp delete mode 100644 sdk/dlls/headcrab.cpp delete mode 100644 sdk/dlls/healthkit.cpp delete mode 100644 sdk/dlls/hgrunt.cpp delete mode 100644 sdk/dlls/hl.def delete mode 100644 sdk/dlls/hl.dsp delete mode 100644 sdk/dlls/hlgl.def delete mode 100644 sdk/dlls/hornet.cpp delete mode 100644 sdk/dlls/hornet.h delete mode 100644 sdk/dlls/hornetgun.cpp delete mode 100644 sdk/dlls/houndeye.cpp delete mode 100644 sdk/dlls/ichthyosaur.cpp delete mode 100644 sdk/dlls/islave.cpp delete mode 100644 sdk/dlls/items.cpp delete mode 100644 sdk/dlls/items.h delete mode 100644 sdk/dlls/leech.cpp delete mode 100644 sdk/dlls/lights.cpp delete mode 100644 sdk/dlls/maprules.cpp delete mode 100644 sdk/dlls/maprules.h delete mode 100644 sdk/dlls/monsterevent.h delete mode 100644 sdk/dlls/monstermaker.cpp delete mode 100644 sdk/dlls/monsters.cpp delete mode 100644 sdk/dlls/monsters.h delete mode 100644 sdk/dlls/monsterstate.cpp delete mode 100644 sdk/dlls/mortar.cpp delete mode 100644 sdk/dlls/mp5.cpp delete mode 100644 sdk/dlls/mpstubb.cpp delete mode 100644 sdk/dlls/msvc10/hl.sln delete mode 100644 sdk/dlls/msvc10/hl.vcxproj delete mode 100644 sdk/dlls/msvc10/hl.vcxproj.filters delete mode 100644 sdk/dlls/msvc11/hl.sln delete mode 100644 sdk/dlls/msvc11/hl.vcxproj delete mode 100644 sdk/dlls/msvc11/hl.vcxproj.filters delete mode 100644 sdk/dlls/multiplay_gamerules.cpp delete mode 100644 sdk/dlls/nihilanth.cpp delete mode 100644 sdk/dlls/nodes.cpp delete mode 100644 sdk/dlls/nodes.h delete mode 100644 sdk/dlls/observer.cpp delete mode 100644 sdk/dlls/osprey.cpp delete mode 100644 sdk/dlls/pathcorner.cpp delete mode 100644 sdk/dlls/plane.cpp delete mode 100644 sdk/dlls/plane.h delete mode 100644 sdk/dlls/plats.cpp delete mode 100644 sdk/dlls/player.cpp delete mode 100644 sdk/dlls/player.h delete mode 100644 sdk/dlls/playermonster.cpp delete mode 100644 sdk/dlls/python.cpp delete mode 100644 sdk/dlls/rat.cpp delete mode 100644 sdk/dlls/roach.cpp delete mode 100644 sdk/dlls/rpg.cpp delete mode 100644 sdk/dlls/satchel.cpp delete mode 100644 sdk/dlls/saverestore.h delete mode 100644 sdk/dlls/schedule.cpp delete mode 100644 sdk/dlls/schedule.h delete mode 100644 sdk/dlls/scientist.cpp delete mode 100644 sdk/dlls/scripted.cpp delete mode 100644 sdk/dlls/scripted.h delete mode 100644 sdk/dlls/scriptevent.h delete mode 100644 sdk/dlls/shotgun.cpp delete mode 100644 sdk/dlls/singleplay_gamerules.cpp delete mode 100644 sdk/dlls/skill.cpp delete mode 100644 sdk/dlls/skill.h delete mode 100644 sdk/dlls/sound.cpp delete mode 100644 sdk/dlls/soundent.cpp delete mode 100644 sdk/dlls/soundent.h delete mode 100644 sdk/dlls/spectator.cpp delete mode 100644 sdk/dlls/spectator.h delete mode 100644 sdk/dlls/squad.h delete mode 100644 sdk/dlls/squadmonster.cpp delete mode 100644 sdk/dlls/squadmonster.h delete mode 100644 sdk/dlls/squeakgrenade.cpp delete mode 100644 sdk/dlls/stats.cpp delete mode 100644 sdk/dlls/subs.cpp delete mode 100644 sdk/dlls/talkmonster.cpp delete mode 100644 sdk/dlls/talkmonster.h delete mode 100644 sdk/dlls/teamplay_gamerules.cpp delete mode 100644 sdk/dlls/teamplay_gamerules.h delete mode 100644 sdk/dlls/tempmonster.cpp delete mode 100644 sdk/dlls/tentacle.cpp delete mode 100644 sdk/dlls/trains.h delete mode 100644 sdk/dlls/triggers.cpp delete mode 100644 sdk/dlls/tripmine.cpp delete mode 100644 sdk/dlls/turret.cpp delete mode 100644 sdk/dlls/util.cpp delete mode 100644 sdk/dlls/util.h delete mode 100644 sdk/dlls/vector.h delete mode 100644 sdk/dlls/weapons.cpp delete mode 100644 sdk/dlls/weapons.h delete mode 100644 sdk/dlls/world.cpp delete mode 100644 sdk/dlls/wpn_shared/hl_wpn_glock.cpp delete mode 100644 sdk/dlls/wxdebug.h delete mode 100644 sdk/dlls/xen.cpp delete mode 100644 sdk/dlls/zombie.cpp delete mode 100644 sdk/engine/APIProxy.h delete mode 100644 sdk/engine/anorms.h delete mode 100644 sdk/engine/archtypes.h delete mode 100644 sdk/engine/cdll_int.h delete mode 100644 sdk/pm_shared/pm_debug.c delete mode 100644 sdk/pm_shared/pm_debug.h delete mode 100644 sdk/pm_shared/pm_defs.h delete mode 100644 sdk/pm_shared/pm_info.h delete mode 100644 sdk/pm_shared/pm_materials.h delete mode 100644 sdk/pm_shared/pm_math.c delete mode 100644 sdk/pm_shared/pm_movevars.h delete mode 100644 sdk/pm_shared/pm_shared.c delete mode 100644 sdk/pm_shared/pm_shared.h create mode 100644 settings.gradle create mode 100644 shared.gradle create mode 100644 shared_icc.gradle create mode 100644 shared_msvc.gradle delete mode 100644 src/asmlib.h delete mode 100644 src/commands_meta.h delete mode 100644 src/conf_meta.cpp delete mode 100644 src/conf_meta.h delete mode 100644 src/engine_api.h delete mode 100644 src/engine_t.h delete mode 100644 src/engineinfo.cpp delete mode 100644 src/engineinfo.h delete mode 100644 src/game_autodetect.cpp delete mode 100644 src/game_autodetect.h delete mode 100644 src/game_support.cpp delete mode 100644 src/games.h delete mode 100644 src/info_name.h delete mode 100644 src/meta_eiface.h delete mode 100644 src/mlist.h delete mode 100644 src/mm_pextensions.h delete mode 100644 src/mplayer.h delete mode 100644 src/mplugin.h delete mode 100644 src/mreg.h delete mode 100644 src/new_baseclass.h delete mode 100644 src/osdep_linkent_win32.cpp delete mode 100644 src/osdep_p.cpp delete mode 100644 src/osdep_p.h delete mode 100644 src/reg_support.h delete mode 100644 src/sdk_util.cpp delete mode 100644 src/tqueue.h delete mode 100644 src/vdate.cpp delete mode 100644 src/vdate.h delete mode 100644 src/vers_meta.h diff --git a/.gitignore b/.gitignore index ad10d73..8c0bc65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +**/build +**/.gradle .idea *.iml **/msvc/Debug* @@ -9,5 +11,10 @@ **/msvc/*.aps **/msvc/*.pch **/msvc/*.txt +**/msvc/start*.bat **/msvc/ipch -**/*.log \ No newline at end of file +**/PublishPath*.txt +**/*.log + +publish +**/appversion.h \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/bin/metamod.dll b/bin/metamod.dll deleted file mode 100644 index 9cda417d534601b635be06a7b275450a9998a664..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210944 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 diff --git a/bin/metamod.so b/bin/metamod.so deleted file mode 100644 index ccda59205200305f37cf8b45939ce68b806b8bf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224472 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 ctx) { + Template tpl = Velocity.getTemplate(tplFile.absolutePath) + if (!tpl) { + throw new RuntimeException("Failed to load velocity template ${tplFile.absolutePath}: not found") + } + + + def velocityContext = new VelocityContext(ctx) + velocityContext.put("_DateTimeFormat", DateTimeFormat) + + def sw = new StringWriter() + tpl.merge(velocityContext, sw) + + return sw.toString() + } +} diff --git a/buildSrc/src/main/groovy/versioning/GitInfo.groovy b/buildSrc/src/main/groovy/versioning/GitInfo.groovy new file mode 100644 index 0000000..3a6a42d --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/GitInfo.groovy @@ -0,0 +1,16 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.joda.time.DateTime + +@CompileStatic @TypeChecked +class GitInfo { + DateTime lastCommitDate + String branch + String tag + Integer countCommit + String commitID + String authorCommit + String urlCommits +} diff --git a/buildSrc/src/main/groovy/versioning/GitVersioner.groovy b/buildSrc/src/main/groovy/versioning/GitVersioner.groovy new file mode 100644 index 0000000..77f86c5 --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/GitVersioner.groovy @@ -0,0 +1,129 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.lib.ObjectId +import org.eclipse.jgit.lib.Repository +import org.eclipse.jgit.lib.StoredConfig +import org.eclipse.jgit.revwalk.RevCommit +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.storage.file.FileRepositoryBuilder +import org.joda.time.DateTime +import org.joda.time.DateTimeZone + +@CompileStatic @TypeChecked +class GitVersioner { + static GitInfo versionForDir(String dir) { + versionForDir(new File(dir)) + } + static int getCountCommit(Repository repo) { + Iterable commits = Git.wrap(repo).log().call() + int count = 0; + commits.each { + count++; + } + + return count; + } + // return last commit excluding merge commit + static RevCommit parseCommitLast(Repository repo) { + Iterable commits = Git.wrap(repo).log().call() + for (RevCommit b : commits) { + if (b.getParents().length > 1) { // it's merge commit ignore it + continue; + } + return b; + } + + return null; + } + static String prepareUrlToCommits(String url) { + if (url == null) { + // default remote url + return "https://bitbucket.org/rehlds/metamod/commits/"; + } + + StringBuilder sb = new StringBuilder(); + String childPath; + int pos = url.indexOf('@'); + if (pos != -1) { + childPath = url.substring(pos + 1, url.lastIndexOf('.git')).replace(':', '/'); + sb.append('https://'); + } else { + pos = url.lastIndexOf('.git'); + childPath = (pos == -1) ? url : url.substring(0, pos); + } + + // support for different links to history of commits + if (url.indexOf('bitbucket.org') != -1) { + sb.append(childPath).append('/commits/'); + } else { + sb.append(childPath).append('/commit/'); + } + + return sb.toString(); + } + static GitInfo versionForDir(File dir) { + FileRepositoryBuilder builder = new FileRepositoryBuilder() + Repository repo = builder.setWorkTree(dir) + .findGitDir() + .build() + + ObjectId head = repo.resolve('HEAD') + if (!head) { + return null + } + + final StoredConfig cfg = repo.getConfig(); + def commit = new RevWalk(repo).parseCommit(head) + def commitLast = parseCommitLast(repo) + int commitCount = getCountCommit(repo) + + def branch = repo.getBranch() + def commitDate = new DateTime(1000L * commit.commitTime, DateTimeZone.UTC) + + String url = null; + String remote_name = cfg.getString("branch", branch, "remote"); + + if (remote_name == null) { + for (String remotes : cfg.getSubsections("remote")) { + if (url != null) { + println 'Found a second remote: (' + remotes + '), url: (' + cfg.getString("remote", remotes, "url") + ')' + continue; + } + + url = cfg.getString("remote", remotes, "url"); + } + } else { + url = cfg.getString("remote", remote_name, "url"); + } + + println 'Debug: Start'; + println ' cfg: (' + cfg + ')'; + println ' branch: (' + branch + ')'; + println ' remote_name: (' + remote_name + ')'; + println ' url: (' + url + ')'; + println 'Debug: End'; + + String urlCommits = prepareUrlToCommits(url); + + if (!commit) { + throw new RuntimeException("Can't find last commit.") + } + + String tag = repo.tags.find { kv -> kv.value.objectId == commit.id }?.key + String headCommitId = commit.getId().abbreviate(7).name(); + String authorCommit = commitLast.getAuthorIdent().getName(); + + return new GitInfo( + lastCommitDate: commitDate, + branch: branch, + tag: tag, + countCommit: commitCount, + commitID: headCommitId, + authorCommit: authorCommit, + urlCommits: urlCommits + ) + } +} diff --git a/buildSrc/src/main/groovy/versioning/MetamodVersionInfo.groovy b/buildSrc/src/main/groovy/versioning/MetamodVersionInfo.groovy new file mode 100644 index 0000000..95d11fc --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/MetamodVersionInfo.groovy @@ -0,0 +1,42 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.ToString +import groovy.transform.TypeChecked +import org.joda.time.DateTime + +@CompileStatic @TypeChecked +@ToString(includeNames = true) +class MetamodVersionInfo { + int majorVersion + int minorVersion + Integer maintenanceVersion + String specialVersion + Integer countCommit + DateTime lastCommitDate + String commitID + String authorCommit + String urlCommits + + String format(String versionSeparator, String suffixSeparator, boolean includeSuffix) { + StringBuilder sb = new StringBuilder() + sb.append(majorVersion).append(versionSeparator).append(minorVersion) + if (maintenanceVersion != null) { + sb.append(versionSeparator).append(maintenanceVersion) + } + + if (specialVersion && includeSuffix) { + sb.append(suffixSeparator).append(specialVersion) + } + + return sb.toString() + } + String asVersion() { + StringBuilder sb = new StringBuilder() + sb.append(majorVersion).append('.' + minorVersion).append('.' + countCommit); + return sb; + } + String asMavenVersion() { + format('.', '-', true) + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e74de4e --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +majorVersion=0 +minorVersion=1 +specialVersion= diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..175c642d9d335ec83dba0b6fa44b04fc18d7768b GIT binary patch literal 52279 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 z z>AoP>@fd7ps@_E&hT+v++kcE4#VhfS*xFx`mqd@zEMH`bPjqWrwN+40wm&+!bM3)$<)VJ+Ib;@78AnKH)%YES~`6)Jf5K!DH=xLr8r|2FlV0^hw z`oGm?eQTT7vT!ttem*tjI}i8HRY1AK;utL@ZA6Y(7q$x(it^>d8eZLiN^=30CtuAK z5PF`oxw%7>=O+schBjGUn}6yb)*3vyP-!I&T*WOn@$`T-P1!jzRJP<5G?b(Nh_U0jQz$=5^Qv_*E!?mvI4$oW^+ zkZY?qUjbBm%m3Yb`;S@uKld^JACh94ivC~TTmBa97I%61*6ah1SZWDsd$ez4B$h&G z!7xdD&m7X>mlNh1=9J{0CErUG!vvneUQ41qIKCjmTDcR<<@KEAPxE{HdH?u;+e7;1 zYufm8c(gnsIl?adqDpNsm)W%1#}2Xs`3YRKpE|7*`+-+v_g+CPYt(%ESUJbW>iV$M zrhhWjX#a6?LJQ!O2L)i+UTD~EQxV}L$tMe@8lTmQ5U%uML=omp7AC!V>N?*LDCwT! zP2w5$t)*H%k${`+Lf}uuKG}JwQh%b5{f_?IL|iANUnzXQc+>Z2*9*xB9g@DJ4Ca?A z?Oeo=-tCck+KjIhuJW-eS?o>YFi1Gy-1Ks|8xYD`%dGY%LOxFCR>)(ttW}n}{}68- z+9eZMz%p##@>QJ)%|O5Vk}sM8{>2R^18XWp(uhi)q>J2ph~Xk5%*293lfN4x)Rfu$ zF<|gTIw)i#)zt4Z2odd60{r~@-kGDnbB<-jJgK9&fm}rsu zVN(Xn4ny-7ld{aGV9p0a1YvV8sY1P+tW@u8RI8>{jq&Zb_g?XD#g zc~vpz$vj$ZzZdsfbqJCcSZXlgSL$`LLsR0uNdnBI*`q@k1}0Li(7(o{>rh#R+>`s= zIIUD$hC#bHDYL_HpI=9K*x^sT&z_f)Q?tc98^rj0|(=y5JZs7Q)DG_hYp=p)ZHo=LmaZH|ijvnyCy zB7g=EJNz(rvEfM}#cRxXmIeZ#@I9Y0k9&M13MX@ATWr*;S9anO3V67>ifWAoH#3p7 z5Fa~e*QR}bwEd=pk}9jdv^o|yR9XdF9Fjul%A#?bXr@^SbyefuWi5MV&Er^FodJ_A zRadJS|5GDOXOTN;qwofl*41^oJLpe4U1gdM|K$XS&BKqJRfv_Et|j}5Bq9P_&U72f zo@O@)UZZrG&EDY-uD(7~jEYwBx}zrx$;ReTy}bx|P(rA7Y`oVlcroDG?)|k5o&D`B zyeqk0UGc+oW39DI8f0r(WKfu|B)xi*;-N*aME2?l<9rP&fJf-*>i9Dtw5C(E&Ag$) zY8AY2X>FudyX~aSq}%c)p5pmq$Offa48quLB|#S11_D zmG&o(z4m!Ck=CH(jWV_-dT)q_nXl#`uzn7N-~b}I>D37*YdgCJ+B=kB`YkHQh{ToI zyV~IVjSKYGJ}0i+pH)Y!ahORxYo5AMeUJmHr;N>s=ren%!RYV7n)4K@As*raC3_jq z=n)bP!PIiJnIJD8>>6h85`&b?6?+}e_>x|LSi=gm6_weV63r9#gowO)#jKrt8HX{Z zOF7}5fiu`Q@iB&p&hkAT4fNiK3bc2En%N@`W=i5*bhjk?eC6EXZjZJmHJt47t0`H| zYiBLz*O^4!uX%O&%(>!+Ode5WV!?U8=JVSjMX%;#?cj0YZ8XT^xR%}=+p&ASC>KK3 zA(nL1qL|SZ+7_s4!cxpJ1Es)9dsyDd@g4zSOs7n`WS18mt)%XJP$cv|BPpnA8^GZIV3-$dZxM)42|bC5DR~aKfv0PNj#q&)T@eS4pRS4)NeWY}q3v-E;?GMXqaX}`gz-Oiz=|uVrthYgkg<9m_Jmk8{ zK7ZPVigG$JhyL8>9eet@bw<(gq#!w__a}lhm_K4eROBu*?#laXl<#YQ&bk{%!OmrG zcd=W|&H7Z{_fv<1KQ;n@x4fw{Q9N$4Gx2ov42wE^(}iI&zg#!>Tr>q|i)?lZJ`8Y+ zrmqRA(annzcr2ttss%GkrCN#Dr;|%^B9Uj~x8PQ=Yshr1bI;%fWh25D$iBh6B*J!G ze{v>r(JxqDzlv!6wvyw58OoEy8|T>u>qoVldBWN!%Y6e`_hh;tGg91vc$DTlK0cT4 zhXC^f-%?#82DBkq6-+j<67)t}nz{iSVYtR0hDWNnvcg`aDT3^xtfB8gD{~IHH3tDY zq}YtrAMp5c^{}s6`}Eq4&Rg(k^#Mn2;BN4aUK|=0Zz;;t!zp&EQ*j?KJhye0C3_vi zwX)3!^N8X7nf$F`vlZ1SNWNUTUx*SDkCK(aFi(_0kh;CrvJdI_KJzIP$2AkIxLBH_ zU975}yqKU6S3F2DP69wh@VmJZ3P~c#?6=--;sA^6n~FXt`mQj9__#0=2tbsr7yQb8 z&rBj!e<#b*kBzzU%3%sxM=qD9VllaZp5)oxop(vfxfFW*6io+TW@IDgxz^$he*RG@ zz|Q^kcS>CiVK+--xL)KIwQ`5vL&OO9$Eo+3Jv09>@e3WmE52jkKKG6B`Rek3%5R;z z9Ng!-hMZ{sv}k+@i75G3m)n5LxG z=JK~C{vU?PykuF$AtAJ|c?fVZUqPke;)?-r98|YMQsr3MVlu2JQQmZBy9hWi=ua6< z3WoPDf2a=8s+rft4(YCb=5p^oxR*OzGd6%cHt7ms;Ck7fG^I&WM_l5$Lv5fU!}v)^ zY1(*%%BgneHg2O3e@{*jd)u zT*4Xon%wg?c`E8EWIW1kd{{glO~kjT%Hux4->Z>4R3s66L7Sn*0WvFbkIypf zu6O3Y3}|GZI#=*vcH7F~wbXZRa5VbxV@tNJmzLUGj(I1B($rsJ5WG;KP<Vp)CZ_KcI-pS4G$(;0ipUX6+3WQ;|~tVNcdzCiwe zrF{idl}pq%(%s!49nvk`ARyAI)Sd(S!*})5i{AU)wfJb|H>)Oo#UZ4iZf`!F7AMZhM&5 z@nXBwa`_4C=jUKxa?BFD?V;NFP}0V3sj!jwXwp{&HLl9nuf|T4GKLKpKF6?FG(@wk2DP38 zL+`Fjl$ygW$H#oG-*?e7JqXIAFZM2`YnSz7nNZ?~{uHlmj9?JmhV92w->qHeN;CY{ z0M5{CC~|01B1f3(NG(G%FY{InlFJGn3dlowT~#VuO)xK#5uPhXqX-9F9gKU>J>h_H+yw9v_4 zXqIJ;Y-2-%GD_eCr%r5;GSEfSfJ|d*{JPBaS~s1ev#hG%ssG}+36q&v_}0u}D8Y1e zJzvK~FjO{Fl6D48@cxb@sxKc$e-;uWVu^iLsw7Vc9Rg9%p2}y24J&2$gEG*RmE@R}WQp>gD57}EgIGTA9wMqD7K>rnI|Nm2p{uD(1e0gu z1YaUZSLCY?U3ko!!dR-oCvffHD16zc*bc&9pT-E?Vso_farS8ozdQ0sr?bgl{<{Wx zn^TEphzbJI4GfG$@gGL(cVnR%oRi{Yl{W1uXLK|eStN+>b5f)}y(kbNug}aPiZS4f z(Eb5V60%X=eJ>IcLF7MVP0*an7iPV2SII9{7L^Q?FDgFPH7|5ua$M!O^!2I^O@uW>Zfgwj#`F5CC?8SZb}8;R z`uICpqWz6b1@6N)WBEa9>-ed5##-Ds2UD{h+KE%F7se^cJ>1*7imm>#*UyF4Be^k7 zK0F`Z_IdtngJpw7eVsHF@iR72_@wdk@bQ__aWcZ=b(YOb@aq@o!IIos9ntQZbWaWY z41+^ooS(27^^Lo`Rd=)4!7_$ypoU4?7wBGCCsuBLf$0r~y;g+vrCH@s;HwaktFmw) zOz*JWP{=sZOvSXV>OQqo?>}YJ&ae)X9dOE&t!k7A#58Rb$vf?WmA0>c3BWw9!=2u< z`^c!-4a~Vismvt@h`Tk)li+&IhqdEIQW~)&iu*c6eBUW2e4ouC;)n*NZm!2vqcXWU9LJ`!n`yrwY|=o79@m7~IK?lRZOO zFkeTrD!PjKETa1y!hBzJ>K8!=6dP&vhISQUk0&Ulp1dJjzz&D(Ft?93ee%Sl4{>Fb#QE)?8~p<4RmEe(bO=yoPF_Qbd*oP{@Iz zDT#@G-04~t1FtzPz(jvU$n)L->{gF3J5#3Ak0$4H7=^gitP@iV%jNYBhjW|ptc=$x z7A%fQN?IpxKG2v{sWlWTCtDj~X!o+x=+ZV6@$~5_;@UUO!XzzpztNZpbrk*Bv6)yA za*$5KvY>3hqFT$0YF=m(l0;8ZSipr|Bz0hJz-Ttx|4b7!4FW)gKC48uU|vNw*wu+w z2F8}Q$}ostt(q!dIIGy~g-(TpH&^Z(NyApjhug`hn$9F6L|qVEtv*^M1T9bdbO>OSii6O9+?m0%MCgaBz^7wbZ7AX< zDOKtxMasbM8qqgSEuF9xYld&uHD)Fs>?xfjVAX3%cm>mjXa_t)Du^Pk@(+=awG=wvTI}T}pRO?i11;-3|r0qQtOt!8mu0*B_T&2=`#!of?yQc%wm9l5!I5Re@e zqsC=6r{iqqZ0rM^#r!(snHnttsqWOqm{dfk$h&kkQjq@uO&0`q>yG*%jneTiB z4Eq!wz;SPTpBxT?oy|3j4 zSfFn(tS|p34kjgdYSyMbOf`;m><=GioUYe~HX)bWq2QZiTi$#&|0?Qhxy=J&L@uqD z0~6d8YXG_22laO6neXwIFo-!D!#J~aK&P>D(8u7RSObXxR!$k^GYJIf(ad$PewSsAGW%~-!_x9QuI1`FS(6S9o{z+svl}Oj%|m{t#haA8 zSPX2gI*|muL5qO1NZ~D~34`l?7fWsr03AxN3jhs0GN!fQLrQE`r5KFK5R}+r{JDk< z&tz}ViW8NAT|+(isj;a{5dx)nl6jKqLTGo0BgFb)7YhwQ5!ViGvEXC?vZcM$zlO-jh3L$|Qk z99IbP`a*rVIj-#X+Ddq!%T0I+O~LfZ15yYc(I|}y{-NZWh{FU?M!nm<5W?l0i_+~@ zYm3*Z-o_VsE#e4J!E&c!OpZ=g+&g``wbv=%tlH48SmSe6SKPPWi(l{V61-yg*0}qw ztN5KD63m5lqg6)HC+-hQYWyxE^q#);TZWmK{k)|(Xa`ZSM(Zo}Wp-AH{G?#@tpXTd zS6EB3&+KyE-?P3g++m%%?ha2p?4a`VZSwzC1$E(3XW+J zt1|VP+&9Xwri>09t}QI6PEV4X3ngHyHBArV zciRd~RRmzd*QhpZYPE*Z7b6puS}i4&5KEEMjx$qEyQ$AQ2eHsPd|XIs%B?>G)xvj9 z&sC51;U|<_T$ILFBANws$)Cf2D4oYp=tX5c^)Is0Xw-U34IhC8!y(cx3AIJrzrh|C z;!(n$KRE0V%$wIL3kIh&R%ey=G+{0)vSj#NFj6A{5#h@Qi8Y7b&Y+x#5oS5rCn>h= zw`FrLchFX#cC++^^8V<tB+icDc~hf)>F-r!aZg{fU^2Y`ibLP^b%2^ L@0Zq5qN+E_t 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lib/libacof32.lib b/lib/libacof32.lib deleted file mode 100644 index f4cf15bdb4e2fbf32bab787b21a3d1cc02f41685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53338 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

?unTC(nq-hrOr#Gb6!8 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%0DFnB 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 |sC-ZAFtG<|8^~K6nU#!aCm1)}5IgA8U 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 z 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 WA&7CzGiC8ewJxPyroY!)dH*j3Klgb6 diff --git a/metamod/build.gradle b/metamod/build.gradle new file mode 100644 index 0000000..c690016 --- /dev/null +++ b/metamod/build.gradle @@ -0,0 +1,184 @@ +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.gradle.language.cpp.CppSourceSet +import org.gradle.language.rc.tasks.WindowsResourceCompile +import org.gradle.nativeplatform.NativeBinarySpec +import versioning.MetamodVersionInfo +import gradlecpp.VelocityUtils + +apply plugin: 'cpp' +apply plugin: 'windows-resources' +apply plugin: IccCompilerPlugin + +List getRcCompileTasks(NativeBinarySpec binary) { + def linkTask = GradleCppUtils.getLinkTask(binary) + + def res = linkTask.taskDependencies.getDependencies(linkTask).findAll { Task t -> t instanceof WindowsResourceCompile } + return res as List +} + +void postEvaluate(NativeBinarySpec b) { + if (GradleCppUtils.windows) { + getRcCompileTasks(b).each { Task t -> + t.dependsOn project.generateAppVersion + } + } else { + // attach generateAppVersion task to all 'compile source' tasks + GradleCppUtils.getCompileTasks(b).each { Task t -> + t.dependsOn project.generateAppVersion + } + } +} + +void setupToolchain(NativeBinarySpec b) +{ + ToolchainConfig cfg = rootProject.createToolchainConfig(b) + cfg.projectInclude(project, '', '/src', '/include/common', '/include/dlls', '/include/engine', '/include/game_shared', '/include/pm_shared', '/include/public') + cfg.singleDefines '__METAMOD_BUILD__', '__BUILD_FAST_METAMOD__'; + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'metamod_pch' + ) + cfg.compilerOptions.args '/Ob2', '/Oi', '/GF', '/GR-', '/GS-' + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + } else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'metamod_pch' + ) + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_vsnprintf': 'vsnprintf', + '_snprintf': 'snprintf' + ]) + + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-msse2', '-fomit-frame-pointer', '-inline-forceinline', '-fvisibility=default', '-fvisibility-inlines-hidden', '-fno-rtti', '-g0', '-s' + } + + ToolchainConfigUtils.apply(project, cfg, b) + + GradleCppUtils.onTasksCreated(project, 'postEvaluate', { + postEvaluate(b) + }) +} + +model { + buildTypes { + debug + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + metamod(NativeLibrarySpec) { + targetPlatform 'x86' + baseName GradleCppUtils.windows ? 'metamod_mm' : 'metamod_mm_i386' + + sources { + metamod_pch(CppSourceSet) { + source { + srcDirs "src" + include "precompiled.cpp" + } + + exportedHeaders { + srcDirs "include" + } + } + metamod_src(CppSourceSet) { + source { + srcDir "src" + srcDir "version" + include "**/*.cpp" + exclude "precompiled.cpp" + } + + exportedHeaders { + srcDirs "include" + } + } + rc { + source { + srcDir "msvc" + include "metamod.rc" + } + exportedHeaders { + srcDirs "msvc" + } + } + } + binaries.all { + NativeBinarySpec b -> project.setupToolchain(b) + } + } + } +} + +afterEvaluate { + project.binaries.all { + NativeBinarySpec binary -> + Tool linker = binary.linker + + if (GradleCppUtils.windows) { + linker.args "/DEF:${projectDir}\\msvc\\metamod.def" + } + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +tasks.clean.doLast { + project.file('version/appversion.h').delete() +} + +task generateAppVersion { + + MetamodVersionInfo verInfo = (MetamodVersionInfo)rootProject.metamodVersionInfo + def tplFile = project.file('version/appversion.vm') + def renderedFile = project.file('version/appversion.h') + + inputs.file tplFile + inputs.file project.file('gradle.properties') + outputs.file renderedFile + inputs.property('version', verInfo.asMavenVersion()) + inputs.property('lastCommitDate', verInfo.lastCommitDate.toString()) + + doLast { + def templateCtx = [ + verInfo: verInfo + ] + + def content = VelocityUtils.renderTemplate(tplFile, templateCtx) + + renderedFile.delete() + renderedFile.write(content, 'utf-8') + + println 'The current Metamod version is ' + verInfo.asVersion().toString() + ', maven version is ' + verInfo.asMavenVersion().toString() + ', commit id: ' + verInfo.commitID.toString() + ', commit author: ' + verInfo.authorCommit.toString() + ', url: (' + verInfo.urlCommits.toString() + ')'; + } +} diff --git a/metamod/include/common/IGameServerData.h b/metamod/include/common/IGameServerData.h new file mode 100644 index 0000000..d431f00 --- /dev/null +++ b/metamod/include/common/IGameServerData.h @@ -0,0 +1,15 @@ +#pragma once + +#include "maintypes.h" +#include "interface.h" + +class IGameServerData : public IBaseInterface { +public: + virtual ~IGameServerData() { }; + + virtual void WriteDataRequest(const void *buffer, int bufferSize) = 0; + + virtual int ReadDataResponse(void *data, int len) = 0; +}; + +#define GAMESERVERDATA_INTERFACE_VERSION "GameServerData001" diff --git a/sdk/common/Sequence.h b/metamod/include/common/Sequence.h similarity index 100% rename from sdk/common/Sequence.h rename to metamod/include/common/Sequence.h diff --git a/metamod/include/common/SteamCommon.h b/metamod/include/common/SteamCommon.h new file mode 100644 index 0000000..364889c --- /dev/null +++ b/metamod/include/common/SteamCommon.h @@ -0,0 +1,703 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +/* +** The copyright to the contents herein is the property of Valve Corporation. +** The contents may be used and/or copied only with the written permission of +** Valve, or in accordance with the terms and conditions stipulated in +** the agreement/contract under which the contents have been supplied. +** +******************************************************************************* +** +** Contents: +** +** Common types used in the Steam DLL interface. +** +** This file is distributed to Steam application developers. +** +** +** +*******************************************************************************/ + +#ifndef INCLUDED_STEAM_COMMON_STEAMCOMMON_H +#define INCLUDED_STEAM_COMMON_STEAMCOMMON_H + +#if defined(_MSC_VER) && (_MSC_VER > 1000) +#pragma once +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Applications should not define STEAM_EXPORTS. */ + +#if defined ( _WIN32 ) + +#ifdef STEAM_EXPORTS +#define STEAM_API __declspec(dllexport) +#else +#define STEAM_API __declspec(dllimport) +#endif + +#define STEAM_CALL __cdecl + +#else + +#define STEAM_API /* */ +#define STEAM_CALL /* */ + +#endif + +typedef void (STEAM_CALL *KeyValueIteratorCallback_t )(const char *Key, const char *Val, void *pvParam); + + +/****************************************************************************** +** +** Exported macros and constants +** +******************************************************************************/ + +/* DEPRECATED -- these are ignored now, all API access is granted on SteamStartup */ +#define STEAM_USING_FILESYSTEM (0x00000001) +#define STEAM_USING_LOGGING (0x00000002) +#define STEAM_USING_USERID (0x00000004) +#define STEAM_USING_ACCOUNT (0x00000008) +#define STEAM_USING_ALL (0x0000000f) +/* END DEPRECATED */ + +#define STEAM_MAX_PATH (255) +#define STEAM_QUESTION_MAXLEN (255) +#define STEAM_SALT_SIZE (8) +#define STEAM_PROGRESS_PERCENT_SCALE (0x00001000) + +/* These are maximum significant string lengths, excluding nul-terminator. */ +#define STEAM_CARD_NUMBER_SIZE (17) +#define STEAM_CARD_HOLDERNAME_SIZE (100) +#define STEAM_CARD_EXPYEAR_SIZE (4) +#define STEAM_CARD_EXPMONTH_SIZE (2) +#define STEAM_CARD_CVV2_SIZE (5) +#define STEAM_BILLING_ADDRESS1_SIZE (128) +#define STEAM_BILLING_ADDRESS2_SIZE (128) +#define STEAM_BILLING_CITY_SIZE (50) +#define STEAM_BILLING_ZIP_SIZE (16) +#define STEAM_BILLING_STATE_SIZE (32) +#define STEAM_BILLING_COUNTRY_SIZE (32) +#define STEAM_BILLING_PHONE_SIZE (20) +#define STEAM_BILLING_EMAIL_ADDRESS_SIZE (100) +#define STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE (20) +#define STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE (200) +#define STEAM_EXTERNAL_ACCOUNTNAME_SIZE (100) +#define STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE (80) +#define STEAM_BILLING_CONFIRMATION_CODE_SIZE (22) +#define STEAM_BILLING_CARD_APPROVAL_CODE_SIZE (100) +#define STEAM_BILLING_TRANS_DATE_SIZE (9) // mm/dd/yy +#define STEAM_BILLING_TRANS_TIME_SIZE (9) // hh:mm:ss + +/****************************************************************************** +** +** Scalar type and enumerated type definitions. +** +******************************************************************************/ + + +typedef unsigned int SteamHandle_t; + +typedef void * SteamUserIDTicketValidationHandle_t; + +typedef unsigned int SteamCallHandle_t; + +#if defined(_MSC_VER) +typedef unsigned __int64 SteamUnsigned64_t; +#else +typedef unsigned long long SteamUnsigned64_t; +#endif + +typedef enum +{ + eSteamSeekMethodSet = 0, + eSteamSeekMethodCur = 1, + eSteamSeekMethodEnd = 2 +} ESteamSeekMethod; + +typedef enum +{ + eSteamBufferMethodFBF = 0, + eSteamBufferMethodNBF = 1 +} ESteamBufferMethod; + +typedef enum +{ + eSteamErrorNone = 0, + eSteamErrorUnknown = 1, + eSteamErrorLibraryNotInitialized = 2, + eSteamErrorLibraryAlreadyInitialized = 3, + eSteamErrorConfig = 4, + eSteamErrorContentServerConnect = 5, + eSteamErrorBadHandle = 6, + eSteamErrorHandlesExhausted = 7, + eSteamErrorBadArg = 8, + eSteamErrorNotFound = 9, + eSteamErrorRead = 10, + eSteamErrorEOF = 11, + eSteamErrorSeek = 12, + eSteamErrorCannotWriteNonUserConfigFile = 13, + eSteamErrorCacheOpen = 14, + eSteamErrorCacheRead = 15, + eSteamErrorCacheCorrupted = 16, + eSteamErrorCacheWrite = 17, + eSteamErrorCacheSession = 18, + eSteamErrorCacheInternal = 19, + eSteamErrorCacheBadApp = 20, + eSteamErrorCacheVersion = 21, + eSteamErrorCacheBadFingerPrint = 22, + + eSteamErrorNotFinishedProcessing = 23, + eSteamErrorNothingToDo = 24, + eSteamErrorCorruptEncryptedUserIDTicket = 25, + eSteamErrorSocketLibraryNotInitialized = 26, + eSteamErrorFailedToConnectToUserIDTicketValidationServer = 27, + eSteamErrorBadProtocolVersion = 28, + eSteamErrorReplayedUserIDTicketFromClient = 29, + eSteamErrorReceiveResultBufferTooSmall = 30, + eSteamErrorSendFailed = 31, + eSteamErrorReceiveFailed = 32, + eSteamErrorReplayedReplyFromUserIDTicketValidationServer = 33, + eSteamErrorBadSignatureFromUserIDTicketValidationServer = 34, + eSteamErrorValidationStalledSoAborted = 35, + eSteamErrorInvalidUserIDTicket = 36, + eSteamErrorClientLoginRateTooHigh = 37, + eSteamErrorClientWasNeverValidated = 38, + eSteamErrorInternalSendBufferTooSmall = 39, + eSteamErrorInternalReceiveBufferTooSmall = 40, + eSteamErrorUserTicketExpired = 41, + eSteamErrorCDKeyAlreadyInUseOnAnotherClient = 42, + + eSteamErrorNotLoggedIn = 101, + eSteamErrorAlreadyExists = 102, + eSteamErrorAlreadySubscribed = 103, + eSteamErrorNotSubscribed = 104, + eSteamErrorAccessDenied = 105, + eSteamErrorFailedToCreateCacheFile = 106, + eSteamErrorCallStalledSoAborted = 107, + eSteamErrorEngineNotRunning = 108, + eSteamErrorEngineConnectionLost = 109, + eSteamErrorLoginFailed = 110, + eSteamErrorAccountPending = 111, + eSteamErrorCacheWasMissingRetry = 112, + eSteamErrorLocalTimeIncorrect = 113, + eSteamErrorCacheNeedsDecryption = 114, + eSteamErrorAccountDisabled = 115, + eSteamErrorCacheNeedsRepair = 116, + eSteamErrorRebootRequired = 117, + + eSteamErrorNetwork = 200, + eSteamErrorOffline = 201 + + +} ESteamError; + + +typedef enum +{ + eNoDetailedErrorAvailable, + eStandardCerrno, + eWin32LastError, + eWinSockLastError, + eDetailedPlatformErrorCount +} EDetailedPlatformErrorType; + +typedef enum /* Filter elements returned by SteamFind{First,Next} */ +{ + eSteamFindLocalOnly, /* limit search to local filesystem */ + eSteamFindRemoteOnly, /* limit search to remote repository */ + eSteamFindAll /* do not limit search (duplicates allowed) */ +} ESteamFindFilter; + + +/****************************************************************************** +** +** Exported structure and complex type definitions. +** +******************************************************************************/ + + +typedef struct +{ + ESteamError eSteamError; + EDetailedPlatformErrorType eDetailedErrorType; + int nDetailedErrorCode; + char szDesc[STEAM_MAX_PATH]; +} TSteamError; + + + +typedef struct +{ + int bIsDir; /* If non-zero, element is a directory; if zero, element is a file */ + unsigned int uSizeOrCount; /* If element is a file, this contains size of file in bytes */ + int bIsLocal; /* If non-zero, reported item is a standalone element on local filesystem */ + char cszName[STEAM_MAX_PATH]; /* Base element name (no path) */ + long lLastAccessTime; /* Seconds since 1/1/1970 (like time_t) when element was last accessed */ + long lLastModificationTime; /* Seconds since 1/1/1970 (like time_t) when element was last modified */ + long lCreationTime; /* Seconds since 1/1/1970 (like time_t) when element was created */ +} TSteamElemInfo; + + +typedef struct +{ + unsigned int uNumSubscriptions; + unsigned int uMaxNameChars; + unsigned int uMaxApps; + +} TSteamSubscriptionStats; + + +typedef struct +{ + unsigned int uNumApps; + unsigned int uMaxNameChars; + unsigned int uMaxInstallDirNameChars; + unsigned int uMaxVersionLabelChars; + unsigned int uMaxLaunchOptions; + unsigned int uMaxLaunchOptionDescChars; + unsigned int uMaxLaunchOptionCmdLineChars; + unsigned int uMaxNumIcons; + unsigned int uMaxIconSize; + unsigned int uMaxDependencies; + +} TSteamAppStats; + +typedef struct +{ + char *szLabel; + unsigned int uMaxLabelChars; + unsigned int uVersionId; + int bIsNotAvailable; +} TSteamAppVersion; + +typedef struct +{ + char *szDesc; + unsigned int uMaxDescChars; + char *szCmdLine; + unsigned int uMaxCmdLineChars; + unsigned int uIndex; + unsigned int uIconIndex; + int bNoDesktopShortcut; + int bNoStartMenuShortcut; + int bIsLongRunningUnattended; + +} TSteamAppLaunchOption; + + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + char *szLatestVersionLabel; + unsigned int uMaxLatestVersionLabelChars; + char *szCurrentVersionLabel; + unsigned int uMaxCurrentVersionLabelChars; + char *szInstallDirName; + unsigned int uMaxInstallDirNameChars; + unsigned int uId; + unsigned int uLatestVersionId; + unsigned int uCurrentVersionId; + unsigned int uMinCacheFileSizeMB; + unsigned int uMaxCacheFileSizeMB; + unsigned int uNumLaunchOptions; + unsigned int uNumIcons; + unsigned int uNumVersions; + unsigned int uNumDependencies; + +} TSteamApp; + +typedef enum +{ + eNoCost = 0, + eBillOnceOnly = 1, + eBillMonthly = 2, + eProofOfPrepurchaseOnly = 3, + eGuestPass = 4, + eHardwarePromo = 5, + eNumBillingTypes, +} EBillingType; + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + unsigned int *puAppIds; + unsigned int uMaxAppIds; + unsigned int uId; + unsigned int uNumApps; + EBillingType eBillingType; + unsigned int uCostInCents; + unsigned int uNumDiscounts; + int bIsPreorder; + int bRequiresShippingAddress; + unsigned int uDomesticShippingCostInCents; + unsigned int uInternationalShippingCostInCents; + bool bIsCyberCafeSubscription; + unsigned int uGameCode; + char szGameCodeDesc[STEAM_MAX_PATH]; + bool bIsDisabled; + bool bRequiresCD; + unsigned int uTerritoryCode; + bool bIsSteam3Subscription; + +} TSteamSubscription; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uDiscountInCents; + unsigned int uNumQualifiers; + +} TSteamSubscriptionDiscount; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uRequiredSubscription; + int bIsDisqualifier; + +} TSteamDiscountQualifier; + +typedef struct TSteamProgress +{ + int bValid; /* non-zero if call provides progress info */ + unsigned int uPercentDone; /* 0 to 100 * STEAM_PROGRESS_PERCENT_SCALE if bValid */ + char szProgress[STEAM_MAX_PATH]; /* additional progress info */ +} TSteamProgress; + +typedef enum +{ + eSteamNotifyTicketsWillExpire, + eSteamNotifyAccountInfoChanged, + eSteamNotifyContentDescriptionChanged, + eSteamNotifyPleaseShutdown, + eSteamNotifyNewContentServer, + eSteamNotifySubscriptionStatusChanged, + eSteamNotifyContentServerConnectionLost, + eSteamNotifyCacheLoadingCompleted, + eSteamNotifyCacheNeedsDecryption, + eSteamNotifyCacheNeedsRepair +} ESteamNotificationCallbackEvent; + + +typedef void(*SteamNotificationCallback_t)(ESteamNotificationCallbackEvent eEvent, unsigned int nData); + + +typedef char SteamPersonalQuestion_t[ STEAM_QUESTION_MAXLEN + 1 ]; + +typedef struct +{ + unsigned char uchSalt[STEAM_SALT_SIZE]; +} SteamSalt_t; + +typedef enum +{ + eVisa = 1, + eMaster = 2, + eAmericanExpress = 3, + eDiscover = 4, + eDinnersClub = 5, + eJCB = 6 +} ESteamPaymentCardType; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardNumber[ STEAM_CARD_NUMBER_SIZE +1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szCardExpYear[ STEAM_CARD_EXPYEAR_SIZE + 1 ]; + char szCardExpMonth[ STEAM_CARD_EXPMONTH_SIZE+ 1 ]; + char szCardCVV2[ STEAM_CARD_CVV2_SIZE + 1 ]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szBillingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + char szBillingEmailAddress[ STEAM_BILLING_EMAIL_ADDRESS_SIZE + 1 ]; + unsigned int uExpectedCostInCents; + unsigned int uExpectedTaxInCents; + /* If the TSteamSubscription says that shipping info is required, */ + /* then the following fields must be filled out. */ + /* If szShippingName is empty, then assumes so are the rest. */ + char szShippingName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szShippingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szShippingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szShippingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szShippingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szShippingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szShippingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szShippingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + unsigned int uExpectedShippingCostInCents; + +} TSteamPaymentCardInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; + + /* A ProofOfPurchase token is not necessarily a nul-terminated string; it may be binary data + (perhaps encrypted). Hence we need a length and an array of bytes. */ + unsigned int uLengthOfBinaryProofOfPurchaseToken; + char cBinaryProofOfPurchaseToken[ STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE + 1 ]; +} TSteamPrepurchaseInfo; + +typedef struct +{ + char szAccountName[ STEAM_EXTERNAL_ACCOUNTNAME_SIZE + 1 ]; + char szPassword[ STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE + 1 ]; +} TSteamExternalBillingInfo; + +typedef enum +{ + ePaymentCardInfo = 1, + ePrepurchasedInfo = 2, + eAccountBillingInfo = 3, + eExternalBillingInfo = 4, /* indirect billing via ISP etc (not supported yet) */ + ePaymentCardReceipt = 5, + ePrepurchaseReceipt = 6, + eEmptyReceipt = 7 +} ESteamSubscriptionBillingInfoType; + +typedef struct +{ + ESteamSubscriptionBillingInfoType eBillingInfoType; + union { + TSteamPaymentCardInfo PaymentCardInfo; + TSteamPrepurchaseInfo PrepurchaseInfo; + TSteamExternalBillingInfo ExternalBillingInfo; + char bUseAccountBillingInfo; + }; + +} TSteamSubscriptionBillingInfo; + +typedef enum +{ + /* Subscribed */ + eSteamSubscriptionOK = 0, /* Subscribed */ + eSteamSubscriptionPending = 1, /* Awaiting transaction completion */ + eSteamSubscriptionPreorder = 2, /* Is currently a pre-order */ + eSteamSubscriptionPrepurchaseTransferred = 3, /* hop to this account */ + /* Unusbscribed */ + eSteamSubscriptionPrepurchaseInvalid = 4, /* Invalid cd-key */ + eSteamSubscriptionPrepurchaseRejected = 5, /* hopped out / banned / etc */ + eSteamSubscriptionPrepurchaseRevoked = 6, /* hop away from this account */ + eSteamSubscriptionPaymentCardDeclined = 7, /* CC txn declined */ + eSteamSubscriptionCancelledByUser = 8, /* Cancelled by client */ + eSteamSubscriptionCancelledByVendor = 9, /* Cancelled by us */ + eSteamSubscriptionPaymentCardUseLimit = 10, /* Card used too many times, potential fraud */ + eSteamSubscriptionPaymentCardAlert = 11, /* Got a "pick up card" or the like from bank */ + eSteamSubscriptionFailed = 12, /* Other Error in subscription data or transaction failed/lost */ + eSteamSubscriptionPaymentCardAVSFailure = 13, /* Card failed Address Verification check */ + eSteamSubscriptionPaymentCardInsufficientFunds = 14, /* Card failed due to insufficient funds */ + eSteamSubscriptionRestrictedCountry = 15 /* The subscription is not available in the user's country */ + +} ESteamSubscriptionStatus; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardLastFourDigits[ 4 + 1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + + // The following are only available after the subscription leaves "pending" status + char szCardApprovalCode[ STEAM_BILLING_CARD_APPROVAL_CODE_SIZE + 1]; + char szTransDate[ STEAM_BILLING_TRANS_DATE_SIZE + 1]; /* mm/dd/yy */ + char szTransTime[ STEAM_BILLING_TRANS_TIME_SIZE + 1]; /* hh:mm:ss */ + unsigned int uPriceWithoutTax; + unsigned int uTaxAmount; + unsigned int uShippingCost; + +} TSteamPaymentCardReceiptInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; +} TSteamPrepurchaseReceiptInfo; + +typedef struct +{ + ESteamSubscriptionStatus eStatus; + ESteamSubscriptionStatus ePreviousStatus; + ESteamSubscriptionBillingInfoType eReceiptInfoType; + char szConfirmationCode[ STEAM_BILLING_CONFIRMATION_CODE_SIZE + 1]; + union { + TSteamPaymentCardReceiptInfo PaymentCardReceiptInfo; + TSteamPrepurchaseReceiptInfo PrepurchaseReceiptInfo; + }; + +} TSteamSubscriptionReceipt; + +typedef enum +{ + ePhysicalBytesReceivedThisSession = 1, + eAppReadyToLaunchStatus = 2, + eAppPreloadStatus = 3, + eAppEntireDepot = 4, + eCacheBytesPresent = 5 +} ESteamAppUpdateStatsQueryType; + +typedef struct +{ + SteamUnsigned64_t uBytesTotal; + SteamUnsigned64_t uBytesPresent; +} TSteamUpdateStats; + +typedef enum +{ + eSteamUserAdministrator = 0x00000001, /* May subscribe, unsubscribe, etc */ + eSteamUserDeveloper = 0x00000002, /* Steam or App developer */ + eSteamUserCyberCafe = 0x00000004 /* CyberCafe, school, etc -- UI should ask for password */ + /* before allowing logout, unsubscribe, etc */ +} ESteamUserTypeFlags; + +typedef enum +{ + eSteamAccountStatusDefault = 0x00000000, + eSteamAccountStatusEmailVerified = 0x00000001, + /* Note: Mask value 0x2 is reserved for future use. (Some, but not all, public accounts already have this set.) */ + eSteamAccountDisabled = 0x00000004 +} ESteamAccountStatusBitFields ; + + +typedef enum +{ + eSteamBootstrapperError = -1, + eSteamBootstrapperDontCheckForUpdate = 0, + eSteamBootstrapperCheckForUpdateAndRerun = 7 + +} ESteamBootStrapperClientAppResult; + +typedef enum +{ + eSteamOnline = 0, + eSteamOffline = 1, + eSteamNoAuthMode = 2, + eSteamBillingOffline = 3 +} eSteamOfflineStatus; + +typedef struct +{ + int eOfflineNow; + int eOfflineNextSession; +} TSteamOfflineStatus; + +typedef struct +{ + unsigned int uAppId; + int bIsSystemDefined; + char szMountPath[STEAM_MAX_PATH]; +} TSteamAppDependencyInfo; + +typedef enum +{ + eSteamOpenFileRegular = 0x0, + eSteamOpenFileIgnoreLocal = 0x1, + eSteamOpenFileChecksumReads = 0x2 +} ESteamOpenFileFlags; + +typedef enum +{ + eSteamValveCDKeyValidationServer = 0, + eSteamHalfLifeMasterServer = 1, + eSteamFriendsServer = 2, + eSteamCSERServer = 3, + eSteamHalfLife2MasterServer = 4, + eSteamRDKFMasterServer = 5, + eMaxServerTypes = 6 +} ESteamServerType; + +/****************************************************************************** +** +** More exported constants +** +******************************************************************************/ + + +#ifdef __cplusplus + +const SteamHandle_t STEAM_INVALID_HANDLE = 0; +const SteamCallHandle_t STEAM_INVALID_CALL_HANDLE = 0; +const SteamUserIDTicketValidationHandle_t STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE = 0; +const unsigned int STEAM_USE_LATEST_VERSION = 0xFFFFFFFF; + +#else + +#define STEAM_INVALID_HANDLE ((SteamHandle_t)(0)) +#define STEAM_INVALID_CALL_HANDLE ((SteamCallHandle_t)(0)) +#define STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE ((SteamUserIDTicketValidationHandle_t)(0)) +#define STEAM_USE_LATEST_VERSION (0xFFFFFFFFu); + +#endif + + +/****************************************************************************** +** Each Steam instance (licensed Steam Service Provider) has a unique SteamInstanceID_t. +** +** Each Steam instance as its own DB of users. +** Each user in the DB has a unique SteamLocalUserID_t (a serial number, with possible +** rare gaps in the sequence). +** +******************************************************************************/ + +typedef unsigned short SteamInstanceID_t; // MUST be 16 bits + + +#if defined ( _WIN32 ) +typedef unsigned __int64 SteamLocalUserID_t; // MUST be 64 bits +#else +typedef unsigned long long SteamLocalUserID_t; // MUST be 64 bits +#endif + +/****************************************************************************** +** +** Applications need to be able to authenticate Steam users from ANY instance. +** So a SteamIDTicket contains SteamGlobalUserID, which is a unique combination of +** instance and user id. +** +** SteamLocalUserID is an unsigned 64-bit integer. +** For platforms without 64-bit int support, we provide access via a union that splits it into +** high and low unsigned 32-bit ints. Such platforms will only need to compare LocalUserIDs +** for equivalence anyway - not perform arithmetic with them. +** +********************************************************************************/ +typedef struct +{ + unsigned int Low32bits; + unsigned int High32bits; +} TSteamSplitLocalUserID; + +typedef struct +{ + SteamInstanceID_t m_SteamInstanceID; + + union + { + SteamLocalUserID_t As64bits; + TSteamSplitLocalUserID Split; + } m_SteamLocalUserID; + +} TSteamGlobalUserID; + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/sdk/common/beamdef.h b/metamod/include/common/beamdef.h similarity index 97% rename from sdk/common/beamdef.h rename to metamod/include/common/beamdef.h index e0d1096..fd77a76 100644 --- a/sdk/common/beamdef.h +++ b/metamod/include/common/beamdef.h @@ -15,9 +15,7 @@ #if !defined ( BEAMDEFH ) #define BEAMDEFH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #define FBEAM_STARTENTITY 0x00000001 diff --git a/sdk/common/cl_entity.h b/metamod/include/common/cl_entity.h similarity index 98% rename from sdk/common/cl_entity.h rename to metamod/include/common/cl_entity.h index 0371a68..a7cd472 100644 --- a/sdk/common/cl_entity.h +++ b/metamod/include/common/cl_entity.h @@ -16,9 +16,7 @@ #if !defined( CL_ENTITYH ) #define CL_ENTITYH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct efrag_s diff --git a/metamod/include/common/com_model.h b/metamod/include/common/com_model.h new file mode 100644 index 0000000..d6e3d42 --- /dev/null +++ b/metamod/include/common/com_model.h @@ -0,0 +1,340 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_model.h +#pragma once + +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +//#define MAX_MODEL_NAME 64 +//#define MAX_MAP_HULLS 4 +//#define MIPLEVELS 4 +//#define NUM_AMBIENTS 4 // automatic ambient sounds +//#define MAXLIGHTMAPS 4 +#define PLANE_ANYZ 5 + +#define ALIAS_Z_CLIP_PLANE 5 + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +#define ALIAS_ONSEAM 0x0020 +#define ALIAS_XY_CLIP_MASK 0x000F + +#define ZISCALE ((float)0x8000) + +#define CACHE_SIZE 32 // used to align key data structures + +//typedef enum +//{ +// mod_brush, +// mod_sprite, +// mod_alias, +// mod_studio +//} modtype_t; + +// must match definition in modelgen.h +//#ifndef SYNCTYPE_T +//#define SYNCTYPE_T +// +//typedef enum +//{ +// ST_SYNC=0, +// ST_RAND +//} synctype_t; +// +//#endif + +//typedef struct +//{ +// float mins[3], maxs[3]; +// float origin[3]; +// int headnode[MAX_MAP_HULLS]; +// int visleafs; // not including the solid leaf 0 +// int firstface, numfaces; +//} dmodel_t; + +// plane_t structure +//typedef struct mplane_s +//{ +// vec3_t normal; // surface normal +// float dist; // closest appoach to origin +// byte type; // for texture axis selection and fast side tests +// byte signbits; // signx + signy<<1 + signz<<1 +// byte pad[2]; +//} mplane_t; + +//typedef struct +//{ +// vec3_t position; +//} mvertex_t; + +//typedef struct +//{ +// unsigned short v[2]; +// unsigned int cachededgeoffset; +//} medge_t; + +//typedef struct texture_s +//{ +// char name[16]; +// unsigned width, height; +// int anim_total; // total tenths in sequence ( 0 = no) +// int anim_min, anim_max; // time for this frame min <=time< max +// struct texture_s *anim_next; // in the animation sequence +// struct texture_s *alternate_anims; // bmodels in frame 1 use these +// unsigned offsets[MIPLEVELS]; // four mip maps stored +// unsigned paloffset; +//} texture_t; + +//typedef struct +//{ +// float vecs[2][4]; // [s/t] unit vectors in world space. +// // [i][3] is the s/t offset relative to the origin. +// // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] +// float mipadjust; // ?? mipmap limits for very small surfaces +// texture_t *texture; +// int flags; // sky or slime, no lightmap or 256 subdivision +//} mtexinfo_t; + +//typedef struct mnode_s +//{ +// // common with leaf +// int contents; // 0, to differentiate from leafs +// int visframe; // node needs to be traversed if current +// +// short minmaxs[6]; // for bounding box culling +// +// struct mnode_s *parent; +// +// // node specific +// mplane_t *plane; +// struct mnode_s *children[2]; +// +// unsigned short firstsurface; +// unsigned short numsurfaces; +//} mnode_t; + +//typedef struct msurface_s msurface_t; +//typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +//struct decal_s +//{ +// decal_t *pnext; // linked list for each surface +// msurface_t *psurface; // Surface id for persistence / unlinking +// short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) +// short dy; +// short texture; // Decal texture +// byte scale; // Pixel scale +// byte flags; // Decal flags +// +// short entityIndex; // Entity this is attached to +//}; + +//typedef struct mleaf_s +//{ +// // common with node +// int contents; // wil be a negative contents number +// int visframe; // node needs to be traversed if current +// +// short minmaxs[6]; // for bounding box culling +// +// struct mnode_s *parent; +// +// // leaf specific +// byte *compressed_vis; +// struct efrag_s *efrags; +// +// msurface_t **firstmarksurface; +// int nummarksurfaces; +// int key; // BSP sequence number for leaf's contents +// byte ambient_sound_level[NUM_AMBIENTS]; +//} mleaf_t; + +//struct msurface_s +//{ +// int visframe; // should be drawn when node is crossed +// +// int dlightframe; // last frame the surface was checked by an animated light +// int dlightbits; // dynamically generated. Indicates if the surface illumination +// // is modified by an animated light. +// +// mplane_t *plane; // pointer to shared plane +// int flags; // see SURF_ #defines +// +// int firstedge; // look up in model->surfedges[], negative numbers +// int numedges; // are backwards edges +// +// // surface generation data +// struct surfcache_s *cachespots[MIPLEVELS]; +// +// short texturemins[2]; // smallest s/t position on the surface. +// short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces +// +// mtexinfo_t *texinfo; +// +// // lighting info +// byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights +// // no one surface can be effected by more than 4 +// // animated lights. +// color24 *samples; +// +// decal_t *pdecals; +//}; + +//typedef struct +//{ +// int planenum; +// short children[2]; // negative numbers are contents +//} dclipnode_t; + +//typedef struct hull_s +//{ +// dclipnode_t *clipnodes; +// mplane_t *planes; +// int firstclipnode; +// int lastclipnode; +// vec3_t clip_mins; +// vec3_t clip_maxs; +//} hull_t; + +typedef struct cache_user_s +{ + void *data; +} cache_user_t; + +//typedef struct model_s +//{ +// char name[ MAX_MODEL_NAME ]; +// qboolean needload; // bmodels and sprites don't cache normally +// +// modtype_t type; +// int numframes; +// synctype_t synctype; +// +// int flags; +// +// // +// // volume occupied by the model +// // +// vec3_t mins, maxs; +// float radius; +// +// // +// // brush model +// // +// int firstmodelsurface, nummodelsurfaces; +// +// int numsubmodels; +// dmodel_t *submodels; +// +// int numplanes; +// mplane_t *planes; +// +// int numleafs; // number of visible leafs, not counting 0 +// struct mleaf_s *leafs; +// +// int numvertexes; +// mvertex_t *vertexes; +// +// int numedges; +// medge_t *edges; +// +// int numnodes; +// mnode_t *nodes; +// +// int numtexinfo; +// mtexinfo_t *texinfo; +// +// int numsurfaces; +// msurface_t *surfaces; +// +// int numsurfedges; +// int *surfedges; +// +// int numclipnodes; +// dclipnode_t *clipnodes; +// +// int nummarksurfaces; +// msurface_t **marksurfaces; +// +// hull_t hulls[MAX_MAP_HULLS]; +// +// int numtextures; +// texture_t **textures; +// +// byte *visdata; +// +// color24 *lightdata; +// +// char *entities; +// +// // +// // additional model data +// // +// cache_user_t cache; // only access through Mod_Extradata +// +//} model_t; + +//typedef vec_t vec4_t[4]; + +typedef struct alight_s +{ + int ambientlight; // clip at 128 + int shadelight; // clip at 192 - ambientlight + vec3_t color; + float *plightvec; +} alight_t; + +typedef struct auxvert_s +{ + float fv[3]; // viewspace x, y +} auxvert_t; + +#include "custom.h" + +//#define MAX_SCOREBOARDNAME 32 + +// Defined in client.h differently +//typedef struct player_info_s +//{ +// // User id on server +// int userid; +// +// // User info string +// char userinfo[ MAX_INFO_STRING ]; +// +// // Name +// char name[ MAX_SCOREBOARDNAME ]; +// +// // Spectator or not, unused +// int spectator; +// +// int ping; +// int packet_loss; +// +// // skin information +// char model[MAX_QPATH]; +// int topcolor; +// int bottomcolor; +// +// // last frame rendered +// int renderframe; +// +// // Gait frame estimation +// int gaitsequence; +// float gaitframe; +// float gaityaw; +// vec3_t prevgaitorigin; +// +// customization_t customdata; +//} player_info_t; diff --git a/sdk/common/con_nprint.h b/metamod/include/common/con_nprint.h similarity index 84% rename from sdk/common/con_nprint.h rename to metamod/include/common/con_nprint.h index 86b865a..b2a1888 100644 --- a/sdk/common/con_nprint.h +++ b/metamod/include/common/con_nprint.h @@ -15,15 +15,13 @@ #if !defined( CON_NPRINTH ) #define CON_NPRINTH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #ifdef __cplusplus extern "C" { #endif - + typedef struct con_nprint_s { int index; // Row # @@ -31,8 +29,8 @@ typedef struct con_nprint_s float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) } con_nprint_t; -void Con_NPrintf( int idx, char *fmt, ... ); -void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... ); +void Con_NPrintf( int idx, const char *fmt, ... ); +void Con_NXPrintf( struct con_nprint_s *info, const char *fmt, ... ); #ifdef __cplusplus } #endif diff --git a/sdk/common/const.h b/metamod/include/common/const.h similarity index 79% rename from sdk/common/const.h rename to metamod/include/common/const.h index 6c5f35b..aa081dc 100644 --- a/sdk/common/const.h +++ b/metamod/include/common/const.h @@ -12,26 +12,43 @@ * without written permission from Valve LLC. * ****/ + #ifndef CONST_H #define CONST_H +#ifdef _WIN32 +#pragma once +#endif + +// Max # of clients allowed in a server. +#define MAX_CLIENTS 32 + +// How many bits to use to encode an edict. +#define MAX_EDICT_BITS 11 // # of bits needed to represent max edicts +// Max # of edicts in a level (2048) +#define MAX_EDICTS (1<flags -#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground -#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) -#define FL_CONVEYOR (1<<2) -#define FL_CLIENT (1<<3) -#define FL_INWATER (1<<4) -#define FL_MONSTER (1<<5) -#define FL_GODMODE (1<<6) -#define FL_NOTARGET (1<<7) -#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself -#define FL_ONGROUND (1<<9) // At rest / on the ground -#define FL_PARTIALGROUND (1<<10) // not all corners are valid -#define FL_WATERJUMP (1<<11) // player jumping out of water +#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground +#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) +#define FL_CONVEYOR (1<<2) +#define FL_CLIENT (1<<3) +#define FL_INWATER (1<<4) +#define FL_MONSTER (1<<5) +#define FL_GODMODE (1<<6) +#define FL_NOTARGET (1<<7) +#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself +#define FL_ONGROUND (1<<9) // At rest / on the ground +#define FL_PARTIALGROUND (1<<10) // not all corners are valid +#define FL_WATERJUMP (1<<11) // player jumping out of water #define FL_FROZEN (1<<12) // Player is frozen for 3rd person camera #define FL_FAKECLIENT (1<<13) // JAC: fake client, simulated server side; don't send network messages to them #define FL_DUCKING (1<<14) // Player flag -- Player is fully crouched @@ -40,7 +57,7 @@ // UNDONE: Do we need these? #define FL_IMMUNE_WATER (1<<17) -#define FL_IMMUNE_SLIME (1<<18) +#define FL_IMMUNE_SLIME (1<<18) #define FL_IMMUNE_LAVA (1<<19) #define FL_PROXY (1<<20) // This is a spectator proxy @@ -49,62 +66,69 @@ #define FL_MONSTERCLIP (1<<23) // Only collide in with monsters who have FL_MONSTERCLIP set #define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. #define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) -#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc. +#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc. #define FL_CUSTOMENTITY (1<<29) // This is a custom entity #define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time #define FL_DORMANT (1<<31) // Entity is dormant, no updates to client +// SV_EmitSound2 flags +#define SND_EMIT2_NOPAS (1<<0) // never to do check PAS +#define SND_EMIT2_INVOKER (1<<1) // do not send to the client invoker + +// Engine edict->spawnflags +#define SF_NOTINDEATHMATCH 0x0800 // Do not spawn when deathmatch and loading entities from a file + // Goes into globalvars_t.trace_flags #define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box // walkmove modes -#define WALKMOVE_NORMAL 0 // normal walkmove -#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type -#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers +#define WALKMOVE_NORMAL 0 // normal walkmove +#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type +#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers // edict->movetype values -#define MOVETYPE_NONE 0 // never moves -//#define MOVETYPE_ANGLENOCLIP 1 -//#define MOVETYPE_ANGLECLIP 2 -#define MOVETYPE_WALK 3 // Player only - moving on the ground -#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this -#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff -#define MOVETYPE_TOSS 6 // gravity/collisions -#define MOVETYPE_PUSH 7 // no clip to world, push and crush -#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity -#define MOVETYPE_FLYMISSILE 9 // extra size to monsters -#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces +#define MOVETYPE_NONE 0 // never moves +//#define MOVETYPE_ANGLENOCLIP 1 +//#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // Player only - moving on the ground +#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this +#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff +#define MOVETYPE_TOSS 6 // gravity/collisions +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces #define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity #define MOVETYPE_FOLLOW 12 // track movement of aiment -#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) +#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) // edict->solid values // NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves // SOLID only effects OTHER entities colliding with this one when they move - UGH! -#define SOLID_NOT 0 // no interaction with other objects -#define SOLID_TRIGGER 1 // touch on edge, but not blocking -#define SOLID_BBOX 2 // touch on edge, block -#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground -#define SOLID_BSP 4 // bsp clip, touch on edge, block +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block // edict->deadflag values -#define DEAD_NO 0 // alive -#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground -#define DEAD_DEAD 2 // dead. lying still. +#define DEAD_NO 0 // alive +#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define DEAD_DEAD 2 // dead. lying still. #define DEAD_RESPAWNABLE 3 #define DEAD_DISCARDBODY 4 -#define DAMAGE_NO 0 -#define DAMAGE_YES 1 -#define DAMAGE_AIM 2 +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 // entity effects -#define EF_BRIGHTFIELD 1 // swirling cloud of particles -#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 -#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin -#define EF_DIMLIGHT 8 // player flashlight +#define EF_BRIGHTFIELD 1 // swirling cloud of particles +#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 +#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin +#define EF_DIMLIGHT 8 // player flashlight #define EF_INVLIGHT 16 // get lighting from ceiling #define EF_NOINTERP 32 // don't interpolate the next frame #define EF_LIGHT 64 // rocket flare glow sprite @@ -120,7 +144,7 @@ // // temp entity events // -#define TE_BEAMPOINTS 0 // beam effect between two points +#define TE_BEAMPOINTS 0 // beam effect between two points // coord coord coord (start position) // coord coord coord (end position) // short (sprite index) @@ -133,7 +157,7 @@ // byte (brightness) // byte (scroll speed in 0.1's) -#define TE_BEAMENTPOINT 1 // beam effect between point and entity +#define TE_BEAMENTPOINT 1 // beam effect between point and entity // short (start entity) // coord coord coord (end position) // short (sprite index) @@ -146,10 +170,10 @@ // byte (brightness) // byte (scroll speed in 0.1's) -#define TE_GUNSHOT 2 // particle effect plus ricochet sound +#define TE_GUNSHOT 2 // particle effect plus ricochet sound // coord coord coord (position) -#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps +#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps // coord coord coord (position) // short (sprite index) // byte (scale in 0.1's) @@ -164,20 +188,20 @@ #define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles -#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound // coord coord coord (position) -#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps +#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps // coord coord coord (position) // short (sprite index) // byte (scale in 0.1's) // byte (framerate) -#define TE_TRACER 6 // tracer effect from point to point +#define TE_TRACER 6 // tracer effect from point to point // coord, coord, coord (start) // coord, coord, coord (end) -#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters // coord, coord, coord (start) // coord, coord, coord (end) // byte (life in 0.1's) @@ -185,7 +209,7 @@ // byte (amplitude in 0.01's) // short (sprite model index) -#define TE_BEAMENTS 8 +#define TE_BEAMENTS 8 // short (start entity) // short (end entity) // short (sprite index) @@ -198,13 +222,13 @@ // byte (brightness) // byte (scroll speed in 0.1's) -#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite // coord coord coord (position) -#define TE_LAVASPLASH 10 // Quake1 lava splash +#define TE_LAVASPLASH 10 // Quake1 lava splash // coord coord coord (position) -#define TE_TELEPORT 11 // Quake1 teleport splash +#define TE_TELEPORT 11 // Quake1 teleport splash // coord coord coord (position) #define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound @@ -371,13 +395,13 @@ // short (sprite index) // short (flags) -#define TE_BLOODSTREAM 101 // particle spray +#define TE_BLOODSTREAM 101 // particle spray // coord coord coord (start position) // coord coord coord (spray vector) // byte (color) // byte (speed) -#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds +#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds // coord coord coord (start position) // coord coord coord (end position) @@ -567,45 +591,45 @@ -#define MSG_BROADCAST 0 // unreliable to all -#define MSG_ONE 1 // reliable to one (msg_entity) -#define MSG_ALL 2 // reliable to all -#define MSG_INIT 3 // write to the init string +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string #define MSG_PVS 4 // Ents in PVS of org #define MSG_PAS 5 // Ents in PAS of org #define MSG_PVS_R 6 // Reliable to PVS #define MSG_PAS_R 7 // Reliable to PAS #define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) -#define MSG_SPEC 9 // Sends to all spectator proxies +#define MSG_SPEC 9 // Sends to all spectator proxies // contents of a spot in the world -#define CONTENTS_EMPTY -1 -#define CONTENTS_SOLID -2 -#define CONTENTS_WATER -3 -#define CONTENTS_SLIME -4 -#define CONTENTS_LAVA -5 -#define CONTENTS_SKY -6 +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 /* These additional contents constants are defined in bspfile.h -#define CONTENTS_ORIGIN -7 // removed at csg time -#define CONTENTS_CLIP -8 // changed to contents_solid -#define CONTENTS_CURRENT_0 -9 -#define CONTENTS_CURRENT_90 -10 -#define CONTENTS_CURRENT_180 -11 -#define CONTENTS_CURRENT_270 -12 -#define CONTENTS_CURRENT_UP -13 -#define CONTENTS_CURRENT_DOWN -14 +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 #define CONTENTS_TRANSLUCENT -15 */ -#define CONTENTS_LADDER -16 +#define CONTENTS_LADDER -16 -#define CONTENT_FLYFIELD -17 -#define CONTENT_GRAVITY_FLYFIELD -18 -#define CONTENT_FOG -19 +#define CONTENT_FLYFIELD -17 +#define CONTENT_GRAVITY_FLYFIELD -18 +#define CONTENT_FOG -19 #define CONTENT_EMPTY -1 #define CONTENT_SOLID -2 -#define CONTENT_WATER -3 +#define CONTENT_WATER -3 #define CONTENT_SLIME -4 #define CONTENT_LAVA -5 #define CONTENT_SKY -6 @@ -613,9 +637,9 @@ // channels #define CHAN_AUTO 0 #define CHAN_WEAPON 1 -#define CHAN_VOICE 2 +#define CHAN_VOICE 2 #define CHAN_ITEM 3 -#define CHAN_BODY 4 +#define CHAN_BODY 4 #define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area #define CHAN_STATIC 6 // allocate channel from the static area #define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network @@ -624,12 +648,12 @@ // attenuation values #define ATTN_NONE 0 -#define ATTN_NORM (float)0.8 +#define ATTN_NORM (float)0.8 #define ATTN_IDLE (float)2 -#define ATTN_STATIC (float)1.25 +#define ATTN_STATIC (float)1.25 // pitch values -#define PITCH_NORM 100 // non-pitch shifted +#define PITCH_NORM 100 // non-pitch shifted #define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high #define PITCH_HIGH 120 @@ -637,10 +661,10 @@ #define VOL_NORM 1.0 // plats -#define PLAT_LOW_TRIGGER 1 +#define PLAT_LOW_TRIGGER 1 // Trains -#define SF_TRAIN_WAIT_RETRIGGER 1 +#define SF_TRAIN_WAIT_RETRIGGER 1 #define SF_TRAIN_START_ON 4 // Train is initially moving #define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains @@ -665,12 +689,12 @@ // Colliding temp entity sounds #define BOUNCE_GLASS BREAK_GLASS -#define BOUNCE_METAL BREAK_METAL +#define BOUNCE_METAL BREAK_METAL #define BOUNCE_FLESH BREAK_FLESH #define BOUNCE_WOOD BREAK_WOOD #define BOUNCE_SHRAP 0x10 #define BOUNCE_SHELL 0x20 -#define BOUNCE_CONCRETE BREAK_CONCRETE +#define BOUNCE_CONCRETE BREAK_CONCRETE #define BOUNCE_SHOTSHELL 0x80 // Temp entity bounce sound types @@ -712,7 +736,7 @@ enum kRenderFxExplode, // Scale up really big! kRenderFxGlowShell, // Glowing Shell kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) - kRenderFxLightMultiplier, //CTM !!!CZERO added to tell the studiorender that the value in iuser2 is a lightmultiplier + kRenderFxLightMultiplier, //CTM !!!CZERO added to tell the studiorender that the value in iuser2 is a lightmultiplier }; @@ -769,15 +793,14 @@ typedef struct typedef struct { - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area qboolean inopen, inwater; - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - plane_t plane; // surface normal at impact - edict_t *ent; // entity the surface is on - int hitgroup; // 0 == generic, non zero is specific body part + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t * ent; // entity the surface is on + int hitgroup; // 0 == generic, non zero is specific body part } trace_t; -#endif - +#endif // CONST_H diff --git a/metamod/include/common/crc.h b/metamod/include/common/crc.h new file mode 100644 index 0000000..44bcf35 --- /dev/null +++ b/metamod/include/common/crc.h @@ -0,0 +1,55 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* crc.h */ +#pragma once + +#include "quakedef.h" + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +typedef unsigned int CRC32_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +void CRC32_Init(CRC32_t *pulCRC); +CRC32_t CRC32_Final(CRC32_t pulCRC); +void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); +void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *pBuffer, int nBuffer); +BOOL CRC_File(CRC32_t *crcvalue, char *pszFileName); + +#ifdef __cplusplus +} +#endif + +byte COM_BlockSequenceCRCByte(byte *base, int length, int sequence); +int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); + +void MD5Init(MD5Context_t *ctx); +void MD5Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len); +void MD5Final(unsigned char digest[16], MD5Context_t *ctx); +void MD5Transform(unsigned int buf[4], const unsigned int in[16]); + +BOOL MD5_Hash_File(unsigned char digest[16], char *pszFileName, BOOL bUsefopen, BOOL bSeed, unsigned int seed[4]); +char *MD5_Print(unsigned char hash[16]); diff --git a/metamod/include/common/cvardef.h b/metamod/include/common/cvardef.h new file mode 100644 index 0000000..cc3a222 --- /dev/null +++ b/metamod/include/common/cvardef.h @@ -0,0 +1,39 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef CVARDEF_H +#define CVARDEF_H + +#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc +#define FCVAR_USERINFO (1<<1) // changes the client's info string +#define FCVAR_SERVER (1<<2) // notifies players when changed +#define FCVAR_EXTDLL (1<<3) // defined by external DLL +#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar + +typedef struct cvar_s +{ + const char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; + +#endif // CVARDEF_H diff --git a/sdk/common/demo_api.h b/metamod/include/common/demo_api.h similarity index 94% rename from sdk/common/demo_api.h rename to metamod/include/common/demo_api.h index 0130679..8284a81 100644 --- a/sdk/common/demo_api.h +++ b/metamod/include/common/demo_api.h @@ -15,9 +15,7 @@ #if !defined ( DEMO_APIH ) #define DEMO_APIH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct demo_api_s diff --git a/sdk/common/director_cmds.h b/metamod/include/common/director_cmds.h similarity index 100% rename from sdk/common/director_cmds.h rename to metamod/include/common/director_cmds.h diff --git a/sdk/common/dlight.h b/metamod/include/common/dlight.h similarity index 94% rename from sdk/common/dlight.h rename to metamod/include/common/dlight.h index 6a4f5b3..f869c98 100644 --- a/sdk/common/dlight.h +++ b/metamod/include/common/dlight.h @@ -15,9 +15,7 @@ #if !defined ( DLIGHTH ) #define DLIGHTH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct dlight_s diff --git a/sdk/common/dll_state.h b/metamod/include/common/dll_state.h similarity index 79% rename from sdk/common/dll_state.h rename to metamod/include/common/dll_state.h index 4065162..ad16296 100644 --- a/sdk/common/dll_state.h +++ b/metamod/include/common/dll_state.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ // // Purpose: // @@ -17,7 +17,7 @@ #define DLL_NORMAL 0 // User hit Esc or something. #define DLL_QUIT 4 // Quit now -#define DLL_RESTART 6 // Switch to launcher for linux, does a quit but returns 1 +#define DLL_RESTART 5 // Switch to launcher for linux, does a quit but returns 1 // DLL Substate info ( not relevant ) #define ENG_NORMAL (1<<0) diff --git a/sdk/common/entity_state.h b/metamod/include/common/entity_state.h similarity index 85% rename from sdk/common/entity_state.h rename to metamod/include/common/entity_state.h index fe4c097..b3d364d 100644 --- a/sdk/common/entity_state.h +++ b/metamod/include/common/entity_state.h @@ -12,14 +12,16 @@ * without written permission from Valve LLC. * ****/ -#if !defined( ENTITY_STATEH ) -#define ENTITY_STATEH + +#ifndef ENTITY_STATE_H +#define ENTITY_STATE_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif +#include "const.h" + + // For entityType below #define ENTITY_NORMAL (1<<0) #define ENTITY_BEAM (1<<1) @@ -33,11 +35,11 @@ struct entity_state_s // Fields which are filled in by routines outside of delta compression int entityType; // Index into cl_entities array for this entity. - int number; + int number; float msg_time; // Message number last time the player/entity state was updated. - int messagenum; + int messagenum; // Fields which can be transitted and reconstructed over the network stream vec3_t origin; @@ -69,7 +71,7 @@ struct entity_state_s vec3_t velocity; // Send bbox down to client for use during prediction. - vec3_t mins; + vec3_t mins; vec3_t maxs; int aiment; @@ -77,37 +79,37 @@ struct entity_state_s int owner; // Friction, for prediction. - float friction; + float friction; // Gravity multiplier - float gravity; + float gravity; // PLAYER SPECIFIC int team; int playerclass; int health; - qboolean spectator; - int weaponmodel; + qboolean spectator; + int weaponmodel; int gaitsequence; // If standing on conveyor, e.g. - vec3_t basevelocity; + vec3_t basevelocity; // Use the crouched hull, or the regular player hull. - int usehull; + int usehull; // Latched buttons last time state updated. - int oldbuttons; + int oldbuttons; // -1 = in air, else pmove entity number - int onground; + int onground; int iStepLeft; // How fast we are falling - float flFallVelocity; + float flFallVelocity; float fov; int weaponanim; // Parametric movement overrides - vec3_t startpos; - vec3_t endpos; - float impacttime; - float starttime; + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; // For mods int iuser1; @@ -187,9 +189,9 @@ typedef struct clientdata_s typedef struct local_state_s { - entity_state_t playerstate; - clientdata_t client; - weapon_data_t weapondata[ 32 ]; + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[ 64 ]; } local_state_t; -#endif // !ENTITY_STATEH +#endif // ENTITY_STATE_H diff --git a/sdk/common/entity_types.h b/metamod/include/common/entity_types.h similarity index 100% rename from sdk/common/entity_types.h rename to metamod/include/common/entity_types.h diff --git a/sdk/common/enums.h b/metamod/include/common/enums.h similarity index 89% rename from sdk/common/enums.h rename to metamod/include/common/enums.h index 1590191..14e2ce3 100644 --- a/sdk/common/enums.h +++ b/metamod/include/common/enums.h @@ -17,11 +17,11 @@ #define ENUMS_H typedef enum netsrc_s - { - NS_CLIENT, - NS_SERVER, - NS_MULTICAST // xxxMO - } netsrc_t; - +{ + NS_CLIENT, + NS_SERVER, + NS_MULTICAST // xxxMO +} netsrc_t; + #endif diff --git a/sdk/common/event_api.h b/metamod/include/common/event_api.h similarity index 97% rename from sdk/common/event_api.h rename to metamod/include/common/event_api.h index c49c25d..722dfe2 100644 --- a/sdk/common/event_api.h +++ b/metamod/include/common/event_api.h @@ -15,9 +15,7 @@ #if !defined ( EVENT_APIH ) #define EVENT_APIH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #define EVENT_API_VERSION 1 diff --git a/sdk/common/event_args.h b/metamod/include/common/event_args.h similarity index 95% rename from sdk/common/event_args.h rename to metamod/include/common/event_args.h index 7d7d9b3..99dd49a 100644 --- a/sdk/common/event_args.h +++ b/metamod/include/common/event_args.h @@ -15,9 +15,7 @@ #if !defined( EVENT_ARGSH ) #define EVENT_ARGSH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // Event was invoked with stated origin diff --git a/sdk/common/event_flags.h b/metamod/include/common/event_flags.h similarity index 97% rename from sdk/common/event_flags.h rename to metamod/include/common/event_flags.h index fb19ae3..43f804f 100644 --- a/sdk/common/event_flags.h +++ b/metamod/include/common/event_flags.h @@ -15,9 +15,7 @@ #if !defined( EVENT_FLAGSH ) #define EVENT_FLAGSH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // Skip local host for event send. diff --git a/sdk/common/hltv.h b/metamod/include/common/hltv.h similarity index 100% rename from sdk/common/hltv.h rename to metamod/include/common/hltv.h diff --git a/sdk/common/in_buttons.h b/metamod/include/common/in_buttons.h similarity index 95% rename from sdk/common/in_buttons.h rename to metamod/include/common/in_buttons.h index 77294ad..4196a2d 100644 --- a/sdk/common/in_buttons.h +++ b/metamod/include/common/in_buttons.h @@ -15,9 +15,7 @@ #ifndef IN_BUTTONS_H #define IN_BUTTONS_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #define IN_ATTACK (1 << 0) diff --git a/sdk/common/ivoicetweak.h b/metamod/include/common/ivoicetweak.h similarity index 91% rename from sdk/common/ivoicetweak.h rename to metamod/include/common/ivoicetweak.h index cb3adb1..da568c5 100644 --- a/sdk/common/ivoicetweak.h +++ b/metamod/include/common/ivoicetweak.h @@ -8,9 +8,7 @@ #ifndef IVOICETWEAK_H #define IVOICETWEAK_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // These provide access to the voice controls. @@ -28,12 +26,12 @@ typedef struct IVoiceTweak_s // without sending to the server. int (*StartVoiceTweakMode)(); // Returns 0 on error. void (*EndVoiceTweakMode)(); - + // Get/set control values. void (*SetControlFloat)(VoiceTweakControl iControl, float value); float (*GetControlFloat)(VoiceTweakControl iControl); - int (*GetSpeakingVolume)(); + int (*GetSpeakingVolume)(); } IVoiceTweak; diff --git a/metamod/include/common/kbutton.h b/metamod/include/common/kbutton.h new file mode 100644 index 0000000..a890ce5 --- /dev/null +++ b/metamod/include/common/kbutton.h @@ -0,0 +1,44 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef KBUTTON_H +#define KBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <31b2a> ../common/kbutton.h:7 */ +typedef struct kbutton_s +{ + int down[2]; + int state; +} kbutton_t; + + +#endif // KBUTTON_H diff --git a/metamod/include/common/mathlib.h b/metamod/include/common/mathlib.h new file mode 100644 index 0000000..d1dbdc9 --- /dev/null +++ b/metamod/include/common/mathlib.h @@ -0,0 +1,127 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#ifdef PLAY_GAMEDLL + +// probably gamedll compiled with flag /fpmath:fasted, +// so we need to use type double, otherwise will be the test failed + +typedef double float_precision; + +#else + +typedef float float_precision; + +#endif // PLAY_GAMEDLL + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec4_t[4]; +typedef int fixed16_t; + +typedef union DLONG_u +{ + int i[2]; + double d; + float f; +} DLONG; + +#define M_PI 3.14159265358979323846 + +#ifdef __cplusplus +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#ifdef clamp +#undef clamp +#endif + +template +const T& min(const T& a, const T& b) { return (a < b) ? a : b; } + +template +const T& max(const T& a, const T& b) { return (a > b) ? a : b; } + +template +const T& clamp(const T& a, const T& min, const T& max) { return (a > max) ? max : (a < min) ? min : a; } + +#else // __cplusplus + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) +#endif // __cplusplus + +// bitwise operators templates +template::type> +inline T operator~ (T a) { return (T)~(type)a; } +template::type> +inline T operator| (T a, T b) { return (T)((type)a | (type)b); } +template::type> +inline T operator& (T a, T b) { return (T)((type)a & (type)b); } +template::type> +inline T operator^ (T a, T b) { return (T)((type)a ^ (type)b); } +template::type> +inline T& operator|= (T& a, T b) { return (T&)((type&)a |= (type)b); } +template::type> +inline T& operator&= (T& a, T b) { return (T&)((type&)a &= (type)b); } +template::type> +inline T& operator^= (T& a, T b) { return (T&)((type&)a ^= (type)b); } + +inline double M_sqrt(int value) { + return sqrt(value); +} + +inline float M_sqrt(float value) { + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_load_ss(&value))); +} + +inline double M_sqrt(double value) { + double ret; + auto v = _mm_load_sd(&value); + _mm_store_sd(&ret, _mm_sqrt_sd(v, v)); + return ret; +} + +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} diff --git a/sdk/common/net_api.h b/metamod/include/common/net_api.h similarity index 98% rename from sdk/common/net_api.h rename to metamod/include/common/net_api.h index df86cca..9551d18 100644 --- a/sdk/common/net_api.h +++ b/metamod/include/common/net_api.h @@ -8,9 +8,7 @@ #if !defined( NET_APIH ) #define NET_APIH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #if !defined ( NETADRH ) diff --git a/sdk/common/netadr.h b/metamod/include/common/netadr.h similarity index 94% rename from sdk/common/netadr.h rename to metamod/include/common/netadr.h index f320f93..304073c 100644 --- a/sdk/common/netadr.h +++ b/metamod/include/common/netadr.h @@ -16,9 +16,7 @@ #ifndef NETADR_H #define NETADR_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef enum diff --git a/sdk/common/nowin.h b/metamod/include/common/nowin.h similarity index 100% rename from sdk/common/nowin.h rename to metamod/include/common/nowin.h diff --git a/sdk/common/parsemsg.cpp b/metamod/include/common/parsemsg.cpp similarity index 94% rename from sdk/common/parsemsg.cpp rename to metamod/include/common/parsemsg.cpp index d58cd3a..6742db2 100644 --- a/sdk/common/parsemsg.cpp +++ b/metamod/include/common/parsemsg.cpp @@ -16,18 +16,6 @@ // parsemsg.cpp // //-------------------------------------------------------------------------------------------------------------- -#if defined(_MSC_VER) && _MSC_VER >= 1400 - #ifndef _CRT_SECURE_NO_DEPRECATE - #define _CRT_SECURE_NO_DEPRECATE - #endif - - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - - #pragma warning(disable: 4996) // deprecated functions -#endif - #include "parsemsg.h" #include @@ -148,8 +136,7 @@ float READ_FLOAT( void ) char* READ_STRING( void ) { static char string[2048]; - size_t l; - int c; + int l,c; string[0] = 0; diff --git a/sdk/common/parsemsg.h b/metamod/include/common/parsemsg.h similarity index 100% rename from sdk/common/parsemsg.h rename to metamod/include/common/parsemsg.h diff --git a/sdk/common/particledef.h b/metamod/include/common/particledef.h similarity index 96% rename from sdk/common/particledef.h rename to metamod/include/common/particledef.h index 66fc920..7e4043a 100644 --- a/sdk/common/particledef.h +++ b/metamod/include/common/particledef.h @@ -15,9 +15,7 @@ #if !defined( PARTICLEDEFH ) #define PARTICLEDEFH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef enum { diff --git a/sdk/common/pmtrace.h b/metamod/include/common/pmtrace.h similarity index 96% rename from sdk/common/pmtrace.h rename to metamod/include/common/pmtrace.h index 24eb062..1784e9c 100644 --- a/sdk/common/pmtrace.h +++ b/metamod/include/common/pmtrace.h @@ -15,9 +15,7 @@ #if !defined( PMTRACEH ) #define PMTRACEH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct diff --git a/metamod/include/common/port.h b/metamod/include/common/port.h new file mode 100644 index 0000000..a0838a7 --- /dev/null +++ b/metamod/include/common/port.h @@ -0,0 +1,119 @@ +// port.h: portability helper +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "archtypes.h" // DAL + +#ifdef _WIN32 + + // Insert your headers here + #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + #define WIN32_EXTRA_LEAN + + #include "winsani_in.h" + #include + #include "winsani_out.h" + + #include + #include + #include + +#else // _WIN32 + + #include + #include + #include // exit() + #include // strncpy() + #include // tolower() + #include + #include + #include + #include + + typedef unsigned char BYTE; + + typedef int32 LONG; + //typedef uint32 ULONG; + + #ifndef ARCHTYPES_H + typedef uint32 ULONG; + #endif + + typedef void *HANDLE; + + #ifndef HMODULE + typedef void *HMODULE; + #endif + + typedef char * LPSTR; + + #define __cdecl + + + #ifdef __linux__ + typedef struct POINT_s + { + int x; + int y; + } POINT; + typedef void *HINSTANCE; + typedef void *HWND; + typedef void *HDC; + typedef void *HGLRC; + + typedef struct RECT_s + { + int left; + int right; + int top; + int bottom; + } RECT; + #endif + + + #ifdef __cplusplus + + //#undef FALSE + //#undef TRUE + + #ifdef OSX + //#else + //const bool FALSE = false; + //const bool TRUE = true; + #endif + #endif + + #ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif + #endif + + #ifdef __cplusplus + inline int ioctlsocket( int d, int cmd, uint32 *argp ) { return ioctl( d, cmd, argp ); } + inline int closesocket( int fd ) { return close( fd ); } + inline char * GetCurrentDirectory( size_t size, char * buf ) { return getcwd( buf, size ); } + inline int WSAGetLastError() { return errno; } + + inline void DebugBreak( void ) { exit( 1 ); } + #endif + + extern char g_szEXEName[ 4096 ]; + + #define _snprintf snprintf + + #if defined(OSX) + #define SO_ARCH_SUFFIX ".dylib" + #else + #if defined ( __x86_64__ ) + #define SO_ARCH_SUFFIX "_amd64.so" + #else + #define SO_ARCH_SUFFIX ".so" + #endif + #endif +#endif + diff --git a/sdk/common/qfont.h b/metamod/include/common/qfont.h similarity index 90% rename from sdk/common/qfont.h rename to metamod/include/common/qfont.h index 8ac6374..2fc8129 100644 --- a/sdk/common/qfont.h +++ b/metamod/include/common/qfont.h @@ -15,15 +15,13 @@ #if !defined( QFONTH ) #define QFONTH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // Font stuff #define NUM_GLYPHS 256 -//#include "basetypes.h" +// does not exist: // #include "basetypes.h" typedef struct { @@ -37,7 +35,7 @@ typedef struct qfont_s int rowcount; int rowheight; charinfo fontinfo[ NUM_GLYPHS ]; - byte data[4]; + unsigned char data[4]; } qfont_t; #endif // qfont.h diff --git a/metamod/include/common/qlimits.h b/metamod/include/common/qlimits.h new file mode 100644 index 0000000..3fad403 --- /dev/null +++ b/metamod/include/common/qlimits.h @@ -0,0 +1,39 @@ +//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ========== +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef QLIMITS_H +#define QLIMITS_H + +#if defined( _WIN32 ) +#pragma once +#endif + +// DATA STRUCTURE INFO + +#define MAX_NUM_ARGVS 50 + +// SYSTEM INFO +#define MAX_QPATH 64 // max length of a game pathname +#define MAX_OSPATH 260 // max length of a filesystem pathname + +#define ON_EPSILON 0.1 // point on plane side epsilon + +#define MAX_LIGHTSTYLE_INDEX_BITS 6 +#define MAX_LIGHTSTYLES (1< ../common/quakedef.h:29 */ +typedef int BOOL; /* size: 4 */ + +// user message +#define MAX_USER_MSG_DATA 192 + +/* <627f> ../common/quakedef.h:137 */ +//moved to com_model.h +//typedef struct cache_user_s +//{ +// void *data; +//} cache_user_t; + +/* <4313b> ../common/quakedef.h:162 */ +typedef int (*pfnUserMsgHook)(const char *, int, void *); diff --git a/sdk/common/r_efx.h b/metamod/include/common/r_efx.h similarity index 98% rename from sdk/common/r_efx.h rename to metamod/include/common/r_efx.h index a877622..4f7b806 100644 --- a/sdk/common/r_efx.h +++ b/metamod/include/common/r_efx.h @@ -15,9 +15,7 @@ #if !defined ( R_EFXH ) #define R_EFXH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // particle_t @@ -118,7 +116,7 @@ typedef struct efx_api_s efx_api_t; struct efx_api_s { - particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); + particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); void ( *R_BlobExplosion ) ( float * org ); void ( *R_Blood ) ( float * org, float * dir, int pcolor, int speed ); void ( *R_BloodSprite ) ( float * org, int colorindex, int modelIndex, int modelIndex2, float size ); diff --git a/sdk/common/r_studioint.h b/metamod/include/common/r_studioint.h similarity index 92% rename from sdk/common/r_studioint.h rename to metamod/include/common/r_studioint.h index a376529..2ddf012 100644 --- a/sdk/common/r_studioint.h +++ b/metamod/include/common/r_studioint.h @@ -8,9 +8,7 @@ #if !defined( R_STUDIOINT_H ) #define R_STUDIOINT_H #if defined( _WIN32 ) -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #define STUDIO_INTERFACE_VERSION 1 @@ -137,17 +135,17 @@ extern r_studio_interface_t *pStudioAPI; typedef struct sv_blending_interface_s { - int version; + int version; - void ( *SV_StudioSetupBones ) ( struct model_s *pModel, - float frame, - int sequence, - const vec3_t angles, - const vec3_t origin, - const byte *pcontroller, - const byte *pblending, - int iBone, - const edict_t *pEdict ); + void ( *SV_StudioSetupBones )( struct model_s *pModel, + float frame, + int sequence, + const vec3_t angles, + const vec3_t origin, + const byte *pcontroller, + const byte *pblending, + int iBone, + const edict_t *pEdict ); } sv_blending_interface_t; #endif // R_STUDIOINT_H diff --git a/sdk/common/ref_params.h b/metamod/include/common/ref_params.h similarity index 100% rename from sdk/common/ref_params.h rename to metamod/include/common/ref_params.h diff --git a/sdk/common/screenfade.h b/metamod/include/common/screenfade.h similarity index 93% rename from sdk/common/screenfade.h rename to metamod/include/common/screenfade.h index 11223df..62c0d25 100644 --- a/sdk/common/screenfade.h +++ b/metamod/include/common/screenfade.h @@ -8,9 +8,7 @@ #if !defined( SCREENFADEH ) #define SCREENFADEH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct screenfade_s diff --git a/sdk/common/studio_event.h b/metamod/include/common/studio_event.h similarity index 93% rename from sdk/common/studio_event.h rename to metamod/include/common/studio_event.h index 0756c65..c79c210 100644 --- a/sdk/common/studio_event.h +++ b/metamod/include/common/studio_event.h @@ -15,9 +15,7 @@ #if !defined( STUDIO_EVENTH ) #define STUDIO_EVENTH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct mstudioevent_s diff --git a/sdk/common/triangleapi.h b/metamod/include/common/triangleapi.h similarity index 97% rename from sdk/common/triangleapi.h rename to metamod/include/common/triangleapi.h index 8f218e1..069a4d6 100644 --- a/sdk/common/triangleapi.h +++ b/metamod/include/common/triangleapi.h @@ -15,9 +15,7 @@ #if !defined( TRIANGLEAPIH ) #define TRIANGLEAPIH #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef enum diff --git a/sdk/common/usercmd.h b/metamod/include/common/usercmd.h similarity index 96% rename from sdk/common/usercmd.h rename to metamod/include/common/usercmd.h index daf78c3..7cdcfe2 100644 --- a/sdk/common/usercmd.h +++ b/metamod/include/common/usercmd.h @@ -15,9 +15,7 @@ #ifndef USERCMD_H #define USERCMD_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif typedef struct usercmd_s diff --git a/metamod/include/common/vmodes.h b/metamod/include/common/vmodes.h new file mode 100644 index 0000000..5d4384f --- /dev/null +++ b/metamod/include/common/vmodes.h @@ -0,0 +1,35 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + + +/* <430ee> ../common/vmodes.h:40 */ +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; diff --git a/sdk/common/weaponinfo.h b/metamod/include/common/weaponinfo.h similarity index 91% rename from sdk/common/weaponinfo.h rename to metamod/include/common/weaponinfo.h index 4b6af25..251a096 100644 --- a/sdk/common/weaponinfo.h +++ b/metamod/include/common/weaponinfo.h @@ -12,12 +12,11 @@ * without written permission from Valve LLC. * ****/ -#if !defined ( WEAPONINFOH ) -#define WEAPONINFOH + +#ifndef WEAPONINFO_H +#define WEAPONINFO_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif // Info about weapons player might have in his/her possession @@ -51,4 +50,4 @@ typedef struct weapon_data_s float fuser4; } weapon_data_t; -#endif +#endif // WEAPONINFO_H diff --git a/metamod/include/common/winsani_in.h b/metamod/include/common/winsani_in.h new file mode 100644 index 0000000..d8c8527 --- /dev/null +++ b/metamod/include/common/winsani_in.h @@ -0,0 +1,7 @@ +#if _MSC_VER >= 1500 // MSVC++ 9.0 (Visual Studio 2008) +#pragma push_macro("ARRAYSIZE") +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif +#define HSPRITE WINDOWS_HSPRITE +#endif diff --git a/metamod/include/common/winsani_out.h b/metamod/include/common/winsani_out.h new file mode 100644 index 0000000..2726950 --- /dev/null +++ b/metamod/include/common/winsani_out.h @@ -0,0 +1,4 @@ +#if _MSC_VER >= 1500 // MSVC++ 9.0 (Visual Studio 2008) +#undef HSPRITE +#pragma pop_macro("ARRAYSIZE") +#endif diff --git a/metamod/include/dlls/activity.h b/metamod/include/dlls/activity.h new file mode 100644 index 0000000..a34b76a --- /dev/null +++ b/metamod/include/dlls/activity.h @@ -0,0 +1,145 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +typedef enum Activity_s +{ + ACT_INVALID = -1, + + ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity + ACT_IDLE, + ACT_GUARD, + ACT_WALK, + ACT_RUN, + ACT_FLY, + ACT_SWIM, + ACT_HOP, + ACT_LEAP, + ACT_FALL, + ACT_LAND, + ACT_STRAFE_LEFT, + ACT_STRAFE_RIGHT, + ACT_ROLL_LEFT, + ACT_ROLL_RIGHT, + ACT_TURN_LEFT, + ACT_TURN_RIGHT, + ACT_CROUCH, + ACT_CROUCHIDLE, + ACT_STAND, + ACT_USE, + ACT_SIGNAL1, + ACT_SIGNAL2, + ACT_SIGNAL3, + ACT_TWITCH, + ACT_COWER, + ACT_SMALL_FLINCH, + ACT_BIG_FLINCH, + ACT_RANGE_ATTACK1, + ACT_RANGE_ATTACK2, + ACT_MELEE_ATTACK1, + ACT_MELEE_ATTACK2, + ACT_RELOAD, + ACT_ARM, + ACT_DISARM, + ACT_EAT, + ACT_DIESIMPLE, + ACT_DIEBACKWARD, + ACT_DIEFORWARD, + ACT_DIEVIOLENT, + ACT_BARNACLE_HIT, + ACT_BARNACLE_PULL, + ACT_BARNACLE_CHOMP, + ACT_BARNACLE_CHEW, + ACT_SLEEP, + ACT_INSPECT_FLOOR, + ACT_INSPECT_WALL, + ACT_IDLE_ANGRY, + ACT_WALK_HURT, + ACT_RUN_HURT, + ACT_HOVER, + ACT_GLIDE, + ACT_FLY_LEFT, + ACT_FLY_RIGHT, + ACT_DETECT_SCENT, + ACT_SNIFF, + ACT_BITE, + ACT_THREAT_DISPLAY, + ACT_FEAR_DISPLAY, + ACT_EXCITED, + ACT_SPECIAL_ATTACK1, + ACT_SPECIAL_ATTACK2, + ACT_COMBAT_IDLE, + ACT_WALK_SCARED, + ACT_RUN_SCARED, + ACT_VICTORY_DANCE, + ACT_DIE_HEADSHOT, + ACT_DIE_CHESTSHOT, + ACT_DIE_GUTSHOT, + ACT_DIE_BACKSHOT, + ACT_FLINCH_HEAD, + ACT_FLINCH_CHEST, + ACT_FLINCH_STOMACH, + ACT_FLINCH_LEFTARM, + ACT_FLINCH_RIGHTARM, + ACT_FLINCH_LEFTLEG, + ACT_FLINCH_RIGHTLEG, + ACT_FLINCH, + ACT_LARGE_FLINCH, + ACT_HOLDBOMB, + ACT_IDLE_FIDGET, + ACT_IDLE_SCARED, + ACT_IDLE_SCARED_FIDGET, + ACT_FOLLOW_IDLE, + ACT_FOLLOW_IDLE_FIDGET, + ACT_FOLLOW_IDLE_SCARED, + ACT_FOLLOW_IDLE_SCARED_FIDGET, + ACT_CROUCH_IDLE, + ACT_CROUCH_IDLE_FIDGET, + ACT_CROUCH_IDLE_SCARED, + ACT_CROUCH_IDLE_SCARED_FIDGET, + ACT_CROUCH_WALK, + ACT_CROUCH_WALK_SCARED, + ACT_CROUCH_DIE, + ACT_WALK_BACK, + ACT_IDLE_SNEAKY, + ACT_IDLE_SNEAKY_FIDGET, + ACT_WALK_SNEAKY, + ACT_WAVE, + ACT_YES, + ACT_NO, + +} Activity; + +typedef struct +{ + int type; + char *name; + +} activity_map_t; + +extern activity_map_t activity_map[]; diff --git a/metamod/include/dlls/activitymap.h b/metamod/include/dlls/activitymap.h new file mode 100644 index 0000000..cf5ddfc --- /dev/null +++ b/metamod/include/dlls/activitymap.h @@ -0,0 +1,111 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#define _A(a)\ + { a, #a } + +activity_map_t activity_map[] = +{ + _A(ACT_IDLE), + _A(ACT_GUARD), + _A(ACT_WALK), + _A(ACT_RUN), + _A(ACT_FLY), + _A(ACT_SWIM), + _A(ACT_HOP), + _A(ACT_LEAP), + _A(ACT_FALL), + _A(ACT_LAND), + _A(ACT_STRAFE_LEFT), + _A(ACT_STRAFE_RIGHT), + _A(ACT_ROLL_LEFT), + _A(ACT_ROLL_RIGHT), + _A(ACT_TURN_LEFT), + _A(ACT_TURN_RIGHT), + _A(ACT_CROUCH), + _A(ACT_CROUCHIDLE), + _A(ACT_STAND), + _A(ACT_USE), + _A(ACT_SIGNAL1), + _A(ACT_SIGNAL2), + _A(ACT_SIGNAL3), + _A(ACT_TWITCH), + _A(ACT_COWER), + _A(ACT_SMALL_FLINCH), + _A(ACT_BIG_FLINCH), + _A(ACT_RANGE_ATTACK1), + _A(ACT_RANGE_ATTACK2), + _A(ACT_MELEE_ATTACK1), + _A(ACT_MELEE_ATTACK2), + _A(ACT_RELOAD), + _A(ACT_ARM), + _A(ACT_DISARM), + _A(ACT_EAT), + _A(ACT_DIESIMPLE), + _A(ACT_DIEBACKWARD), + _A(ACT_DIEFORWARD), + _A(ACT_DIEVIOLENT), + _A(ACT_BARNACLE_HIT), + _A(ACT_BARNACLE_PULL), + _A(ACT_BARNACLE_CHOMP), + _A(ACT_BARNACLE_CHEW), + _A(ACT_SLEEP), + _A(ACT_INSPECT_FLOOR), + _A(ACT_INSPECT_WALL), + _A(ACT_IDLE_ANGRY), + _A(ACT_WALK_HURT), + _A(ACT_RUN_HURT), + _A(ACT_HOVER), + _A(ACT_GLIDE), + _A(ACT_FLY_LEFT), + _A(ACT_FLY_RIGHT), + _A(ACT_DETECT_SCENT), + _A(ACT_SNIFF), + _A(ACT_BITE), + _A(ACT_THREAT_DISPLAY), + _A(ACT_FEAR_DISPLAY), + _A(ACT_EXCITED), + _A(ACT_SPECIAL_ATTACK1), + _A(ACT_SPECIAL_ATTACK2), + _A(ACT_COMBAT_IDLE), + _A(ACT_WALK_SCARED), + _A(ACT_RUN_SCARED), + _A(ACT_VICTORY_DANCE), + _A(ACT_DIE_HEADSHOT), + _A(ACT_DIE_CHESTSHOT), + _A(ACT_DIE_GUTSHOT), + _A(ACT_DIE_BACKSHOT), + _A(ACT_FLINCH_HEAD), + _A(ACT_FLINCH_CHEST), + _A(ACT_FLINCH_STOMACH), + _A(ACT_FLINCH_LEFTARM), + _A(ACT_FLINCH_RIGHTARM), + _A(ACT_FLINCH_LEFTLEG), + _A(ACT_FLINCH_RIGHTLEG), + 0, NULL +}; diff --git a/metamod/include/dlls/airtank.h b/metamod/include/dlls/airtank.h new file mode 100644 index 0000000..3f435a8 --- /dev/null +++ b/metamod/include/dlls/airtank.h @@ -0,0 +1,42 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CAirtank: public CGrenade { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual int BloodColor() = 0; + + int GetState() const { return m_state; } +private: + int m_state; +}; diff --git a/metamod/include/dlls/ammo.h b/metamod/include/dlls/ammo.h new file mode 100644 index 0000000..4b22b9e --- /dev/null +++ b/metamod/include/dlls/ammo.h @@ -0,0 +1,98 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class C9MMAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class CBuckShotAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C556NatoAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C556NatoBoxAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C762NatoAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C45ACPAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C50AEAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C338MagnumAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C57MMAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; + +class C357SIGAmmo: public CBasePlayerAmmo { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; +}; diff --git a/metamod/include/dlls/basemonster.h b/metamod/include/dlls/basemonster.h new file mode 100644 index 0000000..05cb5e3 --- /dev/null +++ b/metamod/include/dlls/basemonster.h @@ -0,0 +1,105 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "activity.h" + +class EHANDLE; + +enum MONSTERSTATE +{ + MONSTERSTATE_NONE = 0, + MONSTERSTATE_IDLE, + MONSTERSTATE_COMBAT, + MONSTERSTATE_ALERT, + MONSTERSTATE_HUNT, + MONSTERSTATE_PRONE, + MONSTERSTATE_SCRIPT, + MONSTERSTATE_PLAYDEAD, + MONSTERSTATE_DEAD +}; + +class CBaseToggle; +class CBaseMonster: public CBaseToggle { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual BOOL TakeHealth(float flHealth, int bitsDamageType) = 0; + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual int BloodColor() = 0; + virtual BOOL IsAlive() = 0; + virtual float ChangeYaw(int speed) = 0; + virtual BOOL HasHumanGibs() = 0; + virtual BOOL HasAlienGibs() = 0; + virtual void FadeMonster() = 0; + virtual void GibMonster() = 0; + virtual Activity GetDeathActivity() = 0; + virtual void BecomeDead() = 0; + virtual BOOL ShouldFadeOnDeath() = 0; + virtual int IRelationship(CBaseEntity *pTarget) = 0; + virtual void PainSound() = 0; + virtual void ResetMaxSpeed() = 0; + virtual void ReportAIState() = 0; + virtual void MonsterInitDead() = 0; + virtual void Look(int iDistance) = 0; + virtual CBaseEntity *BestVisibleEnemy() = 0; + virtual BOOL FInViewCone(CBaseEntity *pEntity) = 0; + virtual BOOL FInViewCone(const Vector *pOrigin) = 0; +public: + void SetConditions(int iConditions) { m_afConditions |= iConditions; } + void ClearConditions(int iConditions) { m_afConditions &= ~iConditions; } + BOOL HasConditions(int iConditions) { return (m_afConditions & iConditions) ? TRUE : FALSE; } + BOOL HasAllConditions(int iConditions) { return ((m_afConditions & iConditions) == iConditions) ? TRUE : FALSE; } + + void Remember(int iMemory) { m_afMemory |= iMemory; } + void Forget(int iMemory) { m_afMemory &= ~iMemory; } + BOOL HasMemory(int iMemory) { return (m_afMemory & iMemory) ? TRUE : FALSE; } + BOOL HasAllMemories(int iMemory) { return ((m_afMemory & iMemory) == iMemory) ? TRUE : FALSE; } + + void StopAnimation() { pev->framerate = 0.0f; } +public: + Activity m_Activity; // what the monster is doing (animation) + Activity m_IdealActivity; // monster should switch to this activity + int m_LastHitGroup; // the last body region that took damage + int m_bitsDamageType; // what types of damage has monster (player) taken + byte m_rgbTimeBasedDamage[8]; + + MONSTERSTATE m_MonsterState; // monster's current state + MONSTERSTATE m_IdealMonsterState; // monster should change to this state + int m_afConditions; + int m_afMemory; + + float m_flNextAttack; // cannot attack again until this time + EHANDLE m_hEnemy; // the entity that the monster is fighting. + EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach + float m_flFieldOfView; // width of monster's field of view ( dot product ) + int m_bloodColor; // color of blood particless + Vector m_HackedGunPos; // HACK until we can query end of gun + Vector m_vecEnemyLKP; // last known position of enemy. (enemy's origin) +}; diff --git a/metamod/include/dlls/bmodels.h b/metamod/include/dlls/bmodels.h new file mode 100644 index 0000000..741ebc6 --- /dev/null +++ b/metamod/include/dlls/bmodels.h @@ -0,0 +1,131 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing. + +#define SF_BRUSH_ACCDCC 16 // brush should accelerate and decelerate when toggled +#define SF_BRUSH_HURT 32 // rotating brush that inflicts pain based on rotation speed +#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. + +#define SF_WALL_START_OFF 0x0001 + +#define SF_CONVEYOR_VISUAL 0x0001 +#define SF_CONVEYOR_NOTSOLID 0x0002 + +#define SF_WORLD_DARK 0x0001 // Fade from black at startup +#define SF_WORLD_TITLE 0x0002 // Display game title at startup +#define SF_WORLD_FORCETEAM 0x0004 // Force teams + +#define FANPITCHMIN 30 +#define FANPITCHMAX 100 + +// This is just a solid wall if not inhibited +class CFuncWall: public CBaseEntity { +public: + virtual void Spawn() = 0; + + // Bmodels don't go across transitions + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CFuncWallToggle: public CFuncWall { +public: + virtual void Spawn() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CFuncConveyor: public CFuncWall { +public: + virtual void Spawn() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +// A simple entity that looks solid but lets you walk through it. +class CFuncIllusionary: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int ObjectCaps() = 0; +}; + +// Monster only clip brush +// +// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set +// in pev->flags +// +// otherwise it will be invisible and not solid. This can be used to keep +// specific monsters out of certain areas +class CFuncMonsterClip: public CFuncWall { +public: + virtual void Spawn() = 0; + + // Clear out func_wall's use function + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CFuncRotating: public CBaseEntity { +public: + // basic functions + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + + float m_flFanFriction; + float m_flAttenuation; + float m_flVolume; + float m_pitch; + int m_sounds; +}; + +class CPendulum: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + float m_accel; // Acceleration + float m_distance; + float m_time; + float m_damp; + float m_maxSpeed; + float m_dampSpeed; + + Vector m_center; + Vector m_start; +}; diff --git a/metamod/include/dlls/bot/cs_bot.h b/metamod/include/dlls/bot/cs_bot.h new file mode 100644 index 0000000..f9f30aa --- /dev/null +++ b/metamod/include/dlls/bot/cs_bot.h @@ -0,0 +1,641 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "bot/cs_gamestate.h" +#include "bot/cs_bot_manager.h" +#include "bot/cs_bot_chatter.h" + +#define PRIMARY_WEAPON_BUY_COUNT 13 +#define SECONDARY_WEAPON_BUY_COUNT 3 + +#define FLAG_PROGRESS_DRAW 0x0 // draw status bar progress +#define FLAG_PROGRESS_START 0x1 // init status bar progress +#define FLAG_PROGRESS_HIDE 0x2 // hide status bar progress + +#define HI_X 0x01 +#define LO_X 0x02 +#define HI_Y 0x04 +#define LO_Y 0x08 +#define HI_Z 0x10 +#define LO_Z 0x20 + +extern int _navAreaCount; +extern int _currentIndex; + +extern struct BuyInfo primaryWeaponBuyInfoCT[PRIMARY_WEAPON_BUY_COUNT]; +extern struct BuyInfo secondaryWeaponBuyInfoCT[SECONDARY_WEAPON_BUY_COUNT]; + +extern struct BuyInfo primaryWeaponBuyInfoT[PRIMARY_WEAPON_BUY_COUNT]; +extern struct BuyInfo secondaryWeaponBuyInfoT[SECONDARY_WEAPON_BUY_COUNT]; + +class CCSBot; +class BotChatterInterface; + +class BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const = 0; +}; + +class IdleState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual const char *GetName() const { return "Idle"; } +}; + +class HuntState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "Hunt"; } +public: + CNavArea *m_huntArea; +}; + +class AttackState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "Attack"; } +public: + enum DodgeStateType + { + STEADY_ON, + SLIDE_LEFT, + SLIDE_RIGHT, + JUMP, + NUM_ATTACK_STATES + } m_dodgeState; + + float m_nextDodgeStateTimestamp; + CountdownTimer m_repathTimer; + float m_scopeTimestamp; + bool m_haveSeenEnemy; + bool m_isEnemyHidden; + float m_reacquireTimestamp; + float m_shieldToggleTimestamp; + bool m_shieldForceOpen; + float m_pinnedDownTimestamp; + bool m_crouchAndHold; + bool m_didAmbushCheck; + bool m_dodge; + bool m_firstDodge; + bool m_isCoward; + CountdownTimer m_retreatTimer; +}; + +class InvestigateNoiseState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "InvestigateNoise"; } +private: + void AttendCurrentNoise(CCSBot *me); + Vector m_checkNoisePosition; +}; + +class BuyState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "Buy"; } +public: + bool m_isInitialDelay; + int m_prefRetries; + int m_prefIndex; + int m_retries; + bool m_doneBuying; + bool m_buyDefuseKit; + bool m_buyGrenade; + bool m_buyShield; + bool m_buyPistol; +}; + +class MoveToState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "MoveTo"; } + + void SetGoalPosition(const Vector &pos) { m_goalPosition = pos; } + void SetRouteType(RouteType route) { m_routeType = route; } + +private: + Vector m_goalPosition; + RouteType m_routeType; + bool m_radioedPlan; + bool m_askedForCover; +}; + +class FetchBombState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual const char *GetName() const { return "FetchBomb"; } +}; + +class PlantBombState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "PlantBomb"; } +}; + +class DefuseBombState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "DefuseBomb"; } +}; + +class HideState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "Hide"; } + +public: + void SetHidingSpot(const Vector &pos) { m_hidingSpot = pos; } + const Vector &GetHidingSpot() const { return m_hidingSpot; } + + void SetSearchArea(CNavArea *area) { m_searchFromArea = area; } + void SetSearchRange(float range) { m_range = range; } + + void SetDuration(float time) { m_duration = time; } + void SetHoldPosition(bool hold) { m_isHoldingPosition = hold; } + + bool IsAtSpot() const { return m_isAtSpot; } + +public: + CNavArea *m_searchFromArea; + float m_range; + + Vector m_hidingSpot; + bool m_isAtSpot; + float m_duration; + bool m_isHoldingPosition; + float m_holdPositionTime; + bool m_heardEnemy; + + float m_firstHeardEnemyTime; + int m_retry; + Vector m_leaderAnchorPos; +}; + +class EscapeFromBombState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "EscapeFromBomb"; } +}; + +class FollowState: public BotState +{ +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "Follow"; } + + void SetLeader(CBaseEntity *leader) { m_leader = leader; } + +public: + EHANDLE m_leader; + Vector m_lastLeaderPos; + bool m_isStopped; + float m_stoppedTimestamp; + + enum LeaderMotionStateType + { + INVALID, + STOPPED, + WALKING, + RUNNING + + } m_leaderMotionState; + + IntervalTimer m_leaderMotionStateTime; + + bool m_isSneaking; + float m_lastSawLeaderTime; + CountdownTimer m_repathInterval; + + IntervalTimer m_walkTime; + bool m_isAtWalkSpeed; + + float m_waitTime; + CountdownTimer m_idleTimer; +}; + +class UseEntityState: public BotState { +public: + virtual void OnEnter(CCSBot *me) {} + virtual void OnUpdate(CCSBot *me) {} + virtual void OnExit(CCSBot *me) {} + virtual const char *GetName() const { return "UseEntity"; } + + void SetEntity(CBaseEntity *entity) { m_entity = entity; } + +private: + EHANDLE m_entity; +}; + +// The Counter-strike Bot +class CCSBot: public CBot { +public: + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; // invoked when injured by something (EXTEND) - returns the amount of damage inflicted + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; // invoked when killed (EXTEND) + virtual void RoundRespawn() = 0; + virtual void Blind(float duration, float holdTime, float fadeTime, int alpha = 255) = 0; // player blinded by a flashbang + virtual void OnTouchingWeapon(CWeaponBox *box) = 0; // invoked when in contact with a CWeaponBox + + virtual bool Initialize(const BotProfile *profile) = 0; // (EXTEND) prepare bot for action + virtual void SpawnBot() = 0; // (EXTEND) spawn the bot into the game + + virtual void Upkeep() = 0; // lightweight maintenance, invoked frequently + virtual void Update() = 0; // heavyweight algorithms, invoked less often + + virtual void Walk() = 0; + virtual bool Jump(bool mustJump = false) = 0; // returns true if jump was started + + virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) = 0; // invoked when event occurs in the game (some events have NULL entity) + + #define CHECK_FOV true + virtual bool IsVisible(const Vector *pos, bool testFOV = false) const = 0; // return true if we can see the point + virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const = 0; // return true if we can see any part of the player + + virtual bool IsEnemyPartVisible(VisiblePartType part) const = 0; // if enemy is visible, return the part we see for our current enemy + +public: + const Vector &GetEyePosition() const + { + m_eyePos = pev->origin + pev->view_ofs; + return m_eyePos; + } +public: + friend class CCSBotManager; + + // TODO: Get rid of these + friend class AttackState; + friend class BuyState; + + char m_name[64]; // copied from STRING(pev->netname) for debugging + + // behavior properties + float m_combatRange; // desired distance between us and them during gunplay + mutable bool m_isRogue; // if true, the bot is a "rogue" and listens to no-one + mutable CountdownTimer m_rogueTimer; + + enum MoraleType + { + TERRIBLE = -3, + BAD = -2, + NEGATIVE = -1, + NEUTRAL = 0, + POSITIVE = 1, + GOOD = 2, + EXCELLENT = 3, + }; + + MoraleType m_morale; // our current morale, based on our win/loss history + bool m_diedLastRound; // true if we died last round + float m_safeTime; // duration at the beginning of the round where we feel "safe" + bool m_wasSafe; // true if we were in the safe time last update + NavRelativeDirType m_blindMoveDir; // which way to move when we're blind + bool m_blindFire; // if true, fire weapon while blinded + + // TODO: implement through CountdownTimer + float m_surpriseDelay; // when we were surprised + float m_surpriseTimestamp; + + bool m_isFollowing; // true if we are following someone + EHANDLE m_leader; // the ID of who we are following + float m_followTimestamp; // when we started following + float m_allowAutoFollowTime; // time when we can auto follow + + CountdownTimer m_hurryTimer; // if valid, bot is in a hurry + + // instances of each possible behavior state, to avoid dynamic memory allocation during runtime + IdleState m_idleState; + HuntState m_huntState; + AttackState m_attackState; + InvestigateNoiseState m_investigateNoiseState; + BuyState m_buyState; + MoveToState m_moveToState; + FetchBombState m_fetchBombState; + PlantBombState m_plantBombState; + DefuseBombState m_defuseBombState; + HideState m_hideState; + EscapeFromBombState m_escapeFromBombState; + FollowState m_followState; + UseEntityState m_useEntityState; + + // TODO: Allow multiple simultaneous state machines (look around, etc) + BotState *m_state; // current behavior state + float m_stateTimestamp; // time state was entered + bool m_isAttacking; // if true, special Attack state is overriding the state machine + + // high-level tasks + enum TaskType + { + SEEK_AND_DESTROY, + PLANT_BOMB, + FIND_TICKING_BOMB, + DEFUSE_BOMB, + GUARD_TICKING_BOMB, + GUARD_BOMB_DEFUSER, + GUARD_LOOSE_BOMB, + GUARD_BOMB_ZONE, + ESCAPE_FROM_BOMB, + HOLD_POSITION, + FOLLOW, + VIP_ESCAPE, + GUARD_VIP_ESCAPE_ZONE, + COLLECT_HOSTAGES, + RESCUE_HOSTAGES, + GUARD_HOSTAGES, + GUARD_HOSTAGE_RESCUE_ZONE, + MOVE_TO_LAST_KNOWN_ENEMY_POSITION, + MOVE_TO_SNIPER_SPOT, + SNIPING, + + NUM_TASKS + }; + TaskType m_task; // our current task + EHANDLE m_taskEntity; // an entity used for our task + + // navigation + Vector m_goalPosition; + EHANDLE m_goalEntity; + + CNavArea *m_currentArea; // the nav area we are standing on + CNavArea *m_lastKnownArea; // the last area we were in + EHANDLE m_avoid; // higher priority player we need to make way for + float m_avoidTimestamp; + bool m_isJumpCrouching; + bool m_isJumpCrouched; + float m_jumpCrouchTimestamp; + + // path navigation data + enum { _MAX_PATH_LENGTH = 256 }; + struct ConnectInfo + { + CNavArea *area; // the area along the path + NavTraverseType how; // how to enter this area from the previous one + Vector pos; // our movement goal position at this point in the path + const CNavLadder *ladder; // if "how" refers to a ladder, this is it + } + m_path[_MAX_PATH_LENGTH]; + int m_pathLength; + int m_pathIndex; + float m_areaEnteredTimestamp; + + CountdownTimer m_repathTimer; // must have elapsed before bot can pathfind again + + mutable CountdownTimer m_avoidFriendTimer; // used to throttle how often we check for friends in our path + mutable bool m_isFriendInTheWay; // true if a friend is blocking our path + CountdownTimer m_politeTimer; // we'll wait for friend to move until this runs out + bool m_isWaitingBehindFriend; // true if we are waiting for a friend to move + + enum LadderNavState + { + APPROACH_ASCENDING_LADDER, // prepare to scale a ladder + APPROACH_DESCENDING_LADDER, // prepare to go down ladder + FACE_ASCENDING_LADDER, + FACE_DESCENDING_LADDER, + MOUNT_ASCENDING_LADDER, // move toward ladder until "on" it + MOUNT_DESCENDING_LADDER, // move toward ladder until "on" it + ASCEND_LADDER, // go up the ladder + DESCEND_LADDER, // go down the ladder + DISMOUNT_ASCENDING_LADDER, // get off of the ladder + DISMOUNT_DESCENDING_LADDER, // get off of the ladder + MOVE_TO_DESTINATION, // dismount ladder and move to destination area + } + m_pathLadderState; + bool m_pathLadderFaceIn; // if true, face towards ladder, otherwise face away + const CNavLadder *m_pathLadder; // the ladder we need to use to reach the next area + NavRelativeDirType m_pathLadderDismountDir; // which way to dismount + float m_pathLadderDismountTimestamp; // time when dismount started + float m_pathLadderEnd; // if ascending, z of top, if descending z of bottom + float m_pathLadderTimestamp; // time when we started using ladder - for timeout check + + CountdownTimer m_mustRunTimer; // if nonzero, bot cannot walk + + // game scenario mechanisms + CSGameState m_gameState; + + // hostages mechanism + byte m_hostageEscortCount; + float m_hostageEscortCountTimestamp; + bool m_isWaitingForHostage; + CountdownTimer m_inhibitWaitingForHostageTimer; + CountdownTimer m_waitForHostageTimer; + + // listening mechanism + Vector m_noisePosition; // position we last heard non-friendly noise + float m_noiseTimestamp; // when we heard it (can get zeroed) + CNavArea *m_noiseArea; // the nav area containing the noise + float m_noiseCheckTimestamp; + PriorityType m_noisePriority; // priority of currently heard noise + bool m_isNoiseTravelRangeChecked; + + // "looking around" mechanism + float m_lookAroundStateTimestamp; // time of next state change + float m_lookAheadAngle; // our desired forward look angle + float m_forwardAngle; // our current forward facing direction + float m_inhibitLookAroundTimestamp; // time when we can look around again + + enum LookAtSpotState + { + NOT_LOOKING_AT_SPOT, // not currently looking at a point in space + LOOK_TOWARDS_SPOT, // in the process of aiming at m_lookAtSpot + LOOK_AT_SPOT, // looking at m_lookAtSpot + NUM_LOOK_AT_SPOT_STATES + } + m_lookAtSpotState; + Vector m_lookAtSpot; // the spot we're currently looking at + PriorityType m_lookAtSpotPriority; + float m_lookAtSpotDuration; // how long we need to look at the spot + float m_lookAtSpotTimestamp; // when we actually began looking at the spot + float m_lookAtSpotAngleTolerance; // how exactly we must look at the spot + bool m_lookAtSpotClearIfClose; // if true, the look at spot is cleared if it gets close to us + const char *m_lookAtDesc; // for debugging + float m_peripheralTimestamp; + + enum { MAX_APPROACH_POINTS = 16 }; + Vector m_approachPoint[MAX_APPROACH_POINTS]; + unsigned char m_approachPointCount; + Vector m_approachPointViewPosition; // the position used when computing current approachPoint set + bool m_isWaitingToTossGrenade; // lining up throw + CountdownTimer m_tossGrenadeTimer; // timeout timer for grenade tossing + + SpotEncounter *m_spotEncounter; // the spots we will encounter as we move thru our current area + float m_spotCheckTimestamp; // when to check next encounter spot + + // TODO: Add timestamp for each possible client to hiding spots + enum { MAX_CHECKED_SPOTS = 64 }; + struct HidingSpotCheckInfo + { + HidingSpot *spot; + float timestamp; + } + m_checkedHidingSpot[MAX_CHECKED_SPOTS]; + int m_checkedHidingSpotCount; + + // view angle mechanism + float m_lookPitch; // our desired look pitch angle + float m_lookPitchVel; + float m_lookYaw; // our desired look yaw angle + float m_lookYawVel; + + // aim angle mechanism + mutable Vector m_eyePos; + Vector m_aimOffset; // current error added to victim's position to get actual aim spot + Vector m_aimOffsetGoal; // desired aim offset + float m_aimOffsetTimestamp; // time of next offset adjustment + float m_aimSpreadTimestamp; // time used to determine max spread as it begins to tighten up + Vector m_aimSpot; // the spot we are currently aiming to fire at + + // attack state data + // behavior modifiers + enum DispositionType + { + ENGAGE_AND_INVESTIGATE, // engage enemies on sight and investigate enemy noises + OPPORTUNITY_FIRE, // engage enemies on sight, but only look towards enemy noises, dont investigate + SELF_DEFENSE, // only engage if fired on, or very close to enemy + IGNORE_ENEMIES, // ignore all enemies - useful for ducking around corners, running away, etc + + NUM_DISPOSITIONS + }; + DispositionType m_disposition; // how we will react to enemies + CountdownTimer m_ignoreEnemiesTimer; // how long will we ignore enemies + mutable EHANDLE m_enemy; // our current enemy + bool m_isEnemyVisible; // result of last visibility test on enemy + unsigned char m_visibleEnemyParts; // which parts of the visible enemy do we see + Vector m_lastEnemyPosition; // last place we saw the enemy + float m_lastSawEnemyTimestamp; + float m_firstSawEnemyTimestamp; + float m_currentEnemyAcquireTimestamp; + float m_enemyDeathTimestamp; // if m_enemy is dead, this is when he died + bool m_isLastEnemyDead; // true if we killed or saw our last enemy die + int m_nearbyEnemyCount; // max number of enemies we've seen recently + unsigned int m_enemyPlace; // the location where we saw most of our enemies + + struct WatchInfo + { + float timestamp; + bool isEnemy; + } + m_watchInfo[MAX_CLIENTS]; + mutable EHANDLE m_bomber; // points to bomber if we can see him + + int m_nearbyFriendCount; // number of nearby teammates + mutable EHANDLE m_closestVisibleFriend; // the closest friend we can see + mutable EHANDLE m_closestVisibleHumanFriend; // the closest human friend we can see + + CBasePlayer *m_attacker; // last enemy that hurt us (may not be same as m_enemy) + float m_attackedTimestamp; // when we were hurt by the m_attacker + + int m_lastVictimID; // the entindex of the last victim we killed, or zero + bool m_isAimingAtEnemy; // if true, we are trying to aim at our enemy + bool m_isRapidFiring; // if true, RunUpkeep() will toggle our primary attack as fast as it can + IntervalTimer m_equipTimer; // how long have we had our current weapon equipped + float m_fireWeaponTimestamp; + + // reaction time system + enum { MAX_ENEMY_QUEUE = 20 }; + struct ReactionState + { + // NOTE: player position & orientation is not currently stored separately + EHANDLE player; + bool isReloading; + bool isProtectedByShield; + } + m_enemyQueue[MAX_ENEMY_QUEUE]; // round-robin queue for simulating reaction times + + byte m_enemyQueueIndex; + byte m_enemyQueueCount; + byte m_enemyQueueAttendIndex; // index of the timeframe we are "conscious" of + + // stuck detection + bool m_isStuck; + float m_stuckTimestamp; // time when we got stuck + Vector m_stuckSpot; // the location where we became stuck + NavRelativeDirType m_wiggleDirection; + float m_wiggleTimestamp; + float m_stuckJumpTimestamp; // time for next jump when stuck + + enum { MAX_VEL_SAMPLES = 5 }; + float m_avgVel[MAX_VEL_SAMPLES]; + int m_avgVelIndex; + int m_avgVelCount; + Vector m_lastOrigin; + + // chatter mechanism + GameEventType m_lastRadioCommand; // last radio command we recieved + + float m_lastRadioRecievedTimestamp; // time we recieved a radio message + float m_lastRadioSentTimestamp; // time when we send a radio message + EHANDLE m_radioSubject; // who issued the radio message + Vector m_radioPosition; // position referred to in radio message + float m_voiceFeedbackStartTimestamp; + float m_voiceFeedbackEndTimestamp; // new-style "voice" chatter gets voice feedback + BotChatterInterface m_chatter; + + // learn map mechanism + const CNavNode *m_navNodeList; + CNavNode *m_currentNode; + NavDirType m_generationDir; + NavAreaList::iterator m_analyzeIter; + + enum ProcessType + { + PROCESS_NORMAL, + PROCESS_LEARN, + PROCESS_ANALYZE_ALPHA, + PROCESS_ANALYZE_BETA, + PROCESS_SAVE, + } + m_processMode; + CountdownTimer m_mumbleTimer; + CountdownTimer m_booTimer; + CountdownTimer m_relocateTimer; +}; diff --git a/metamod/include/dlls/bot/cs_bot_chatter.h b/metamod/include/dlls/bot/cs_bot_chatter.h new file mode 100644 index 0000000..4f56b96 --- /dev/null +++ b/metamod/include/dlls/bot/cs_bot_chatter.h @@ -0,0 +1,337 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define UNDEFINED_COUNT 0xFFFF +#define MAX_PLACES_PER_MAP 64 +#define UNDEFINED_SUBJECT (-1) +#define COUNT_MANY 4 // equal to or greater than this is "many" + +class CCSBot; +class BotChatterInterface; + +typedef unsigned int PlaceCriteria; +typedef unsigned int CountCriteria; + +// A meme is a unit information that bots use to +// transmit information to each other via the radio +class BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const = 0; // cause the given bot to act on this meme +}; + +class BotAllHostagesGoneMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +}; + +class BotHostageBeingTakenMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +}; + +class BotHelpMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +public: + Place m_place; +}; + +class BotBombsiteStatusMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +public: + enum StatusType { CLEAR, PLANTED }; + int m_zoneIndex; // the bombsite + StatusType m_status; // whether it is cleared or the bomb is there (planted) +}; + +class BotBombStatusMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme + +public: + CSGameState::BombState m_state; + Vector m_pos; +}; + +class BotFollowMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +}; + +class BotDefendHereMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +public: + Vector m_pos; +}; + +class BotWhereBombMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +}; + +class BotRequestReportMeme: public BotMeme { +public: + virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme +}; + +enum BotStatementType +{ + REPORT_VISIBLE_ENEMIES, + REPORT_ENEMY_ACTION, + REPORT_MY_CURRENT_TASK, + REPORT_MY_INTENTION, + REPORT_CRITICAL_EVENT, + REPORT_REQUEST_HELP, + REPORT_REQUEST_INFORMATION, + REPORT_ROUND_END, + REPORT_MY_PLAN, + REPORT_INFORMATION, + REPORT_EMOTE, + REPORT_ACKNOWLEDGE, // affirmative or negative + REPORT_ENEMIES_REMAINING, + REPORT_FRIENDLY_FIRE, + REPORT_KILLED_FRIEND, + //REPORT_ENEMY_LOST + + NUM_BOT_STATEMENT_TYPES, +}; + +// BotSpeakables are the smallest unit of bot chatter. +// They represent a specific wav file of a phrase, and the criteria for which it is useful +class BotSpeakable { +public: + char *m_phrase; + float m_duration; + PlaceCriteria m_place; + CountCriteria m_count; +}; + +typedef std::vector BotSpeakableVector; +typedef std::vector BotVoiceBankVector; + +// The BotPhrase class is a collection of Speakables associated with a name, ID, and criteria +class BotPhrase { +public: + const char *GetName() const { return m_name; } + Place GetID() const { return m_id; } + GameEventType GetRadioEquivalent() const { return m_radioEvent; } + bool IsImportant() const { return m_isImportant; } // return true if this phrase is part of an important statement + bool IsPlace() const { return m_isPlace; } +public: + friend class BotPhraseManager; + char *m_name; + Place m_id; + bool m_isPlace; // true if this is a Place phrase + GameEventType m_radioEvent; + bool m_isImportant; // mission-critical statement + + mutable BotVoiceBankVector m_voiceBank; // array of voice banks (arrays of speakables) + std::vector m_count; // number of speakables + mutable std::vector< int > m_index; // index of next speakable to return + int m_numVoiceBanks; // number of voice banks that have been initialized + + mutable PlaceCriteria m_placeCriteria; + mutable CountCriteria m_countCriteria; +}; + +typedef std::list BotPhraseList; + +// The BotPhraseManager is a singleton that provides an interface to all BotPhrase collections +class BotPhraseManager { +public: + const BotPhraseList *GetPlaceList() const { return &m_placeList; } + + // return time last statement of given type was emitted by a teammate for the given place + float GetPlaceStatementInterval(Place place) const; + + // set time of last statement of given type was emitted by a teammate for the given place + void ResetPlaceStatementInterval(Place place) const; + +public: + int FindPlaceIndex(Place where) const; + + // master list of all phrase collections + BotPhraseList m_list; + + // master list of all Place phrases + BotPhraseList m_placeList; + + struct PlaceTimeInfo + { + Place placeID; + IntervalTimer timer; + }; + + mutable PlaceTimeInfo m_placeStatementHistory[MAX_PLACES_PER_MAP]; + mutable int m_placeCount; +}; + +inline int BotPhraseManager::FindPlaceIndex(Place where) const +{ + for (int i = 0; i < m_placeCount; ++i) + { + if (m_placeStatementHistory[i].placeID == where) + return i; + } + + if (m_placeCount < MAX_PLACES_PER_MAP) + { + m_placeStatementHistory[++m_placeCount].placeID = where; + m_placeStatementHistory[++m_placeCount].timer.Invalidate(); + return m_placeCount - 1; + } + + return -1; +} + +inline float BotPhraseManager::GetPlaceStatementInterval(Place place) const +{ + int index = FindPlaceIndex(place); + + if (index < 0) + return 999999.9f; + + if (index >= m_placeCount) + return 999999.9f; + + return m_placeStatementHistory[index].timer.GetElapsedTime(); +} + +inline void BotPhraseManager::ResetPlaceStatementInterval(Place place) const +{ + int index = FindPlaceIndex(place); + + if (index < 0) + return; + + if (index >= m_placeCount) + return; + + m_placeStatementHistory[index].timer.Reset(); +} + +// Statements are meaningful collections of phrases +class BotStatement { +public: + BotChatterInterface *GetChatter() const { return m_chatter; } + BotStatementType GetType() const { return m_type; } // return the type of statement this is + bool HasSubject() const { return (m_subject != UNDEFINED_SUBJECT); } + void SetSubject(int playerID) { m_subject = playerID; } // who this statement is about + int GetSubject() const { return m_subject; } // who this statement is about + void SetPlace(Place where) { m_place = where; } // explicitly set place + + void SetStartTime(float timestamp) { m_startTime = timestamp; } // define the earliest time this statement can be spoken + float GetStartTime() const { return m_startTime; } + bool IsSpeaking() const { return m_isSpeaking; } // return true if this statement is currently being spoken + float GetTimestamp() const { return m_timestamp; } // get time statement was created (but not necessarily started talking) + +public: + friend class BotChatterInterface; + + BotChatterInterface *m_chatter; // the chatter system this statement is part of + BotStatement *m_next, *m_prev; // linked list hooks + + BotStatementType m_type; // what kind of statement this is + int m_subject; // who this subject is about + Place m_place; // explicit place - note some phrases have implicit places as well + BotMeme *m_meme; // a statement can only have a single meme for now + + float m_timestamp; // time when message was created + float m_startTime; // the earliest time this statement can be spoken + float m_expireTime; // time when this statement is no longer valid + float m_speakTimestamp; // time when message began being spoken + bool m_isSpeaking; // true if this statement is current being spoken + + float m_nextTime; // time for next phrase to begin + + enum { MAX_BOT_PHRASES = 4 }; + enum ContextType + { + CURRENT_ENEMY_COUNT, + REMAINING_ENEMY_COUNT, + SHORT_DELAY, + LONG_DELAY, + ACCUMULATE_ENEMIES_DELAY, + }; + struct + { + bool isPhrase; + union + { + const BotPhrase *phrase; + ContextType context; + }; + + } + m_statement[MAX_BOT_PHRASES]; + + enum { MAX_BOT_CONDITIONS = 4 }; + enum ConditionType + { + IS_IN_COMBAT, + RADIO_SILENCE, + ENEMIES_REMAINING, + NUM_CONDITIONS, + }; + + ConditionType m_condition[MAX_BOT_CONDITIONS]; // conditions that must be true for the statement to be said + int m_conditionCount; + + int m_index; // m_index refers to the phrase currently being spoken, or -1 if we havent started yet + int m_count; +}; + +// This class defines the interface to the bot radio chatter system +class BotChatterInterface { +public: + CCSBot *GetOwner() const { return m_me; } + int GetPitch() const { return m_pitch; } + bool SeesAtLeastOneEnemy() const { return m_seeAtLeastOneEnemy; } +public: + BotStatement *m_statementList; // list of all active/pending messages for this bot + void ReportEnemies(); // track nearby enemy count and generate enemy activity statements + bool ShouldSpeak() const; // return true if we speaking makes sense now + CCSBot *m_me; // the bot this chatter is for + bool m_seeAtLeastOneEnemy; + float m_timeWhenSawFirstEnemy; + bool m_reportedEnemies; + bool m_requestedBombLocation; // true if we already asked where the bomb has been planted + int m_pitch; + IntervalTimer m_needBackupInterval; + IntervalTimer m_spottedBomberInterval; + IntervalTimer m_scaredInterval; + IntervalTimer m_planInterval; + CountdownTimer m_spottedLooseBombTimer; + CountdownTimer m_heardNoiseTimer; + CountdownTimer m_escortingHostageTimer; +}; + +extern BotPhraseManager *TheBotPhrases; diff --git a/metamod/include/dlls/bot/cs_bot_manager.h b/metamod/include/dlls/bot/cs_bot_manager.h new file mode 100644 index 0000000..38f3d60 --- /dev/null +++ b/metamod/include/dlls/bot/cs_bot_manager.h @@ -0,0 +1,145 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +extern CBotManager *TheBots; + +// The manager for Counter-Strike specific bots +class CCSBotManager: public CBotManager { +public: + virtual void ClientDisconnect(CBasePlayer *pPlayer) = 0; + virtual BOOL ClientCommand(CBasePlayer *pPlayer, const char *pcmd) = 0; + + virtual void ServerActivate() = 0; + virtual void ServerDeactivate() = 0; + + virtual void ServerCommand(const char *pcmd) = 0; + virtual void AddServerCommand(const char *cmd) = 0; + virtual void AddServerCommands() = 0; + + virtual void RestartRound() = 0; // (EXTEND) invoked when a new round begins + virtual void StartFrame() = 0; // (EXTEND) called each frame + + virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) = 0; + virtual unsigned int GetPlayerPriority(CBasePlayer *player) const = 0; // return priority of player (0 = max pri) + virtual bool IsImportantPlayer(CBasePlayer *player) const = 0; // return true if player is important to scenario (VIP, bomb carrier, etc) + +public: + // the supported game scenarios + enum GameScenarioType + { + SCENARIO_DEATHMATCH, + SCENARIO_DEFUSE_BOMB, + SCENARIO_RESCUE_HOSTAGES, + SCENARIO_ESCORT_VIP + }; + GameScenarioType GetScenario() const { return m_gameScenario; } + + // "zones" + // depending on the game mode, these are bomb zones, rescue zones, etc. + enum { MAX_ZONES = 4 }; // max # of zones in a map + enum { MAX_ZONE_NAV_AREAS = 16 }; // max # of nav areas in a zone + struct Zone + { + CBaseEntity *m_entity; // the map entity + CNavArea *m_area[MAX_ZONE_NAV_AREAS]; // nav areas that overlap this zone + int m_areaCount; + Vector m_center; + bool m_isLegacy; // if true, use pev->origin and 256 unit radius as zone + int m_index; + Extent m_extent; + }; + + const Zone *GetZone(int i) const { return &m_zone[i]; } + int GetZoneCount() const { return m_zoneCount; } + + // pick a zone at random and return it + const Zone *GetRandomZone() const + { + if (!m_zoneCount) + return NULL; + + return &m_zone[RANDOM_LONG(0, m_zoneCount - 1)]; + } + + bool IsBombPlanted() const { return m_isBombPlanted; } // returns true if bomb has been planted + float GetBombPlantTimestamp() const { return m_bombPlantTimestamp; } // return time bomb was planted + bool IsTimeToPlantBomb() const { return (gpGlobals->time >= m_earliestBombPlantTimestamp); } // return true if it's ok to try to plant bomb + CBasePlayer *GetBombDefuser() const { return m_bombDefuser; } // return the player currently defusing the bomb, or NULL + CBaseEntity *GetLooseBomb() { return m_looseBomb; } // return the bomb if it is loose on the ground + CNavArea *GetLooseBombArea() const { return m_looseBombArea; } // return area that bomb is in/near + + float GetLastSeenEnemyTimestamp() const { return m_lastSeenEnemyTimestamp; } // return the last time anyone has seen an enemy + void SetLastSeenEnemyTimestamp() { m_lastSeenEnemyTimestamp = gpGlobals->time; } + + float GetRoundStartTime() const { return m_roundStartTimestamp; } + float GetElapsedRoundTime() const { return gpGlobals->time - m_roundStartTimestamp; } // return the elapsed time since the current round began + + bool IsDefenseRushing() const { return m_isDefenseRushing; } // returns true if defense team has "decided" to rush this round + bool IsRoundOver() const { return m_isRoundOver; } // return true if the round has ended + + unsigned int GetNavPlace() const { return m_navPlace; } + void SetNavPlace(unsigned int place) { m_navPlace = place; } + +public: + GameScenarioType m_gameScenario; // what kind of game are we playing + + Zone m_zone[MAX_ZONES]; + int m_zoneCount; + + bool m_isBombPlanted; // true if bomb has been planted + float m_bombPlantTimestamp; // time bomb was planted + float m_earliestBombPlantTimestamp; // don't allow planting until after this time has elapsed + CBasePlayer *m_bombDefuser; // the player currently defusing a bomb + EHANDLE m_looseBomb; // will be non-NULL if bomb is loose on the ground + CNavArea *m_looseBombArea; // area that bomb is is/near + + bool m_isRoundOver; // true if the round has ended + float m_radioMsgTimestamp[24][2]; + + float m_lastSeenEnemyTimestamp; + float m_roundStartTimestamp; // the time when the current round began + + bool m_isDefenseRushing; // whether defensive team is rushing this round or not + + unsigned int m_navPlace; + CountdownTimer m_respawnTimer; + bool m_isRespawnStarted; + bool m_canRespawn; + bool m_bServerActive; +}; + +inline int OtherTeam(int team) +{ + return (team == TERRORIST) ? CT : TERRORIST; +} + +inline CCSBotManager *TheCSBots() +{ + return reinterpret_cast(TheBots); +} diff --git a/metamod/include/dlls/bot/cs_gamestate.h b/metamod/include/dlls/bot/cs_gamestate.h new file mode 100644 index 0000000..769575f --- /dev/null +++ b/metamod/include/dlls/bot/cs_gamestate.h @@ -0,0 +1,90 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CCSBot; + +// This class represents the game state as known by a particular bot +class CSGameState { +public: + // bomb defuse scenario + enum BombState + { + MOVING, // being carried by a Terrorist + LOOSE, // loose on the ground somewhere + PLANTED, // planted and ticking + DEFUSED, // the bomb has been defused + EXPLODED, // the bomb has exploded + }; + + bool IsBombMoving() const { return (m_bombState == MOVING); } + bool IsBombLoose() const { return (m_bombState == LOOSE); } + bool IsBombPlanted() const { return (m_bombState == PLANTED); } + bool IsBombDefused() const { return (m_bombState == DEFUSED); } + bool IsBombExploded() const { return (m_bombState == EXPLODED); } + +public: + CCSBot *m_owner; // who owns this gamestate + bool m_isRoundOver; // true if round is over, but no yet reset + + // bomb defuse scenario + BombState GetBombState() { return m_bombState; } + BombState m_bombState; // what we think the bomb is doing + + IntervalTimer m_lastSawBomber; + Vector m_bomberPos; + + IntervalTimer m_lastSawLooseBomb; + Vector m_looseBombPos; + + bool m_isBombsiteClear[4]; // corresponds to zone indices in CCSBotManager + int m_bombsiteSearchOrder[4]; // randomized order of bombsites to search + int m_bombsiteCount; + int m_bombsiteSearchIndex; // the next step in the search + + int m_plantedBombsite; // zone index of the bombsite where the planted bomb is + + bool m_isPlantedBombPosKnown; // if true, we know the exact location of the bomb + Vector m_plantedBombPos; + + // hostage rescue scenario + struct HostageInfo + { + CHostage *hostage; + Vector knownPos; + bool isValid; + bool isAlive; + bool isFree; // not being escorted by a CT + } + m_hostage[MAX_HOSTAGES]; + int m_hostageCount; // number of hostages left in map + CountdownTimer m_validateInterval; + + bool m_allHostagesRescued; // if true, so every hostages been is rescued + bool m_haveSomeHostagesBeenTaken; // true if a hostage has been moved by a CT (and we've seen it) +}; diff --git a/metamod/include/dlls/buttons.h b/metamod/include/dlls/buttons.h new file mode 100644 index 0000000..087417a --- /dev/null +++ b/metamod/include/dlls/buttons.h @@ -0,0 +1,104 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_BUTTON_DONTMOVE 1 +#define SF_ROTBUTTON_NOTSOLID 1 +#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated +#define SF_BUTTON_SPARK_IF_OFF 64 // button sparks in OFF state +#define SF_BUTTON_TOUCH_ONLY 256 // button only fires as a result of USE key. + +#define SF_GLOBAL_SET 1 // Set global state to initial state on spawn + +#define SF_MULTI_INIT 1 + +// Make this button behave like a door (HACKHACK) +// This will disable use and make the button solid +// rotating buttons were made SOLID_NOT by default since their were some +// collision problems with them... +#define SF_MOMENTARY_DOOR 0x0001 + +#define SF_SPARK_TOOGLE 32 +#define SF_SPARK_IF_OFF 64 + +#define SF_BTARGET_USE 0x0001 +#define SF_BTARGET_ON 0x0002 + +class CEnvGlobal: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + string_t m_globalstate; + int m_triggermode; + int m_initialstate; +}; + +class CRotButton: public CBaseButton { +public: + virtual void Spawn() = 0; +}; + +class CMomentaryRotButton: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_lastUsed; + int m_direction; + float m_returnSpeed; + Vector m_start; + Vector m_end; + int m_sounds; +}; + +class CEnvSpark: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; +public: + float m_flDelay; +}; + +class CButtonTarget: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int ObjectCaps() = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; diff --git a/metamod/include/dlls/cbase.h b/metamod/include/dlls/cbase.h new file mode 100644 index 0000000..4817034 --- /dev/null +++ b/metamod/include/dlls/cbase.h @@ -0,0 +1,375 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "util.h" +#include "monsterevent.h" + +class CSave; +class CRestore; +class CBasePlayer; +class CBaseEntity; +class CBaseMonster; +class CBasePlayerItem; +class CSquadMonster; +class CCSEntity; + +class CBaseEntity { +public: + // Constructor. Set engine to use C/C++ callback functions + // pointers to engine data + entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it + + // path corners + CBaseEntity *m_pGoalEnt; // path corner we are heading towards + CBaseEntity *m_pLink; // used for temporary link-list operations. + + // initialization functions + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Activate() = 0; + + // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) + virtual void SetObjectCollisionBox() = 0; + + // Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames + // still realize that they are teammates. (overridden for monsters that form groups) + virtual int Classify() = 0; + virtual void DeathNotice(entvars_t *pevChild) = 0; + + virtual void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual BOOL TakeHealth(float flHealth, int bitsDamageType) = 0; + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual int BloodColor() = 0; + virtual void TraceBleed(float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) = 0; + virtual BOOL IsTriggered(CBaseEntity *pActivator) = 0; + virtual CBaseMonster *MyMonsterPointer() = 0; + virtual CSquadMonster *MySquadMonsterPointer() = 0; + virtual int GetToggleState() = 0; + virtual void AddPoints(int score, BOOL bAllowNegativeScore) = 0; + virtual void AddPointsToTeam(int score, BOOL bAllowNegativeScore) = 0; + virtual BOOL AddPlayerItem(CBasePlayerItem *pItem) = 0; + virtual BOOL RemovePlayerItem(CBasePlayerItem *pItem) = 0; + virtual int GiveAmmo(int iAmount, char *szName, int iMax) = 0; + virtual float GetDelay() = 0; + virtual int IsMoving() = 0; + virtual void OverrideReset() = 0; + virtual int DamageDecal(int bitsDamageType) = 0; + + // This is ONLY used by the node graph to test movement through a door + virtual void SetToggleState(int state) = 0; + virtual void StartSneaking() = 0; + virtual void StopSneaking() = 0; + virtual BOOL OnControls(entvars_t *onpev) = 0; + virtual BOOL IsSneaking() = 0; + virtual BOOL IsAlive() = 0; + virtual BOOL IsBSPModel() = 0; + virtual BOOL ReflectGauss() = 0; + virtual BOOL HasTarget(string_t targetname) = 0; + virtual BOOL IsInWorld() = 0; + virtual BOOL IsPlayer() = 0; + virtual BOOL IsNetClient() = 0; + virtual const char *TeamID() = 0; + + virtual CBaseEntity *GetNextTarget() = 0; + + // fundamental callbacks + void (CBaseEntity::*m_pfnThink)(); + void (CBaseEntity::*m_pfnTouch)(CBaseEntity *pOther); + void (CBaseEntity::*m_pfnUse)(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + void (CBaseEntity::*m_pfnBlocked)(CBaseEntity *pOther); + + virtual void Think() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType = USE_OFF, float value = 0.0f) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; + + virtual CBaseEntity *Respawn() = 0; + virtual void UpdateOwner() = 0; + virtual BOOL FBecomeProne() = 0; + + virtual Vector Center() = 0; // center point of entity + virtual Vector EyePosition() = 0; // position of eyes + virtual Vector EarPosition() = 0; // position of ears + virtual Vector BodyTarget(const Vector &posSrc) = 0; // position to shoot at + + virtual int Illumination() = 0; + virtual BOOL FVisible(CBaseEntity *pEntity) = 0; + virtual BOOL FVisible(const Vector &vecOrigin) = 0; +public: + static CBaseEntity *Instance(edict_t *pent) { return (CBaseEntity *)GET_PRIVATE(pent ? pent : ENT(0)); } + static CBaseEntity *Instance(entvars_t *pev) { return Instance(ENT(pev)); } + static CBaseEntity *Instance(int offset) { return Instance(ENT(offset)); } + + edict_t *edict() { return ENT(pev); } + EOFFSET eoffset() { return OFFSET(pev); } + int entindex() { return ENTINDEX(edict()); } +public: + CCSEntity *m_pEntity; // NOTE: it was replaced on member "int *current_ammo" because it is useless. + + // We use this variables to store each ammo count. + float currentammo; + int maxammo_buckshot; + int ammo_buckshot; + int maxammo_9mm; + int ammo_9mm; + int maxammo_556nato; + int ammo_556nato; + int maxammo_556natobox; + int ammo_556natobox; + int maxammo_762nato; + int ammo_762nato; + int maxammo_45acp; + int ammo_45acp; + int maxammo_50ae; + int ammo_50ae; + int maxammo_338mag; + int ammo_338mag; + int maxammo_57mm; + int ammo_57mm; + int maxammo_357sig; + int ammo_357sig; + + // Special stuff for grenades and knife. + float m_flStartThrow; + float m_flReleaseThrow; + int m_iSwing; + + // client has left the game + bool has_disconnected; +}; + +class CPointEntity: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int ObjectCaps() = 0; +}; + + +// generic Delay entity +class CBaseDelay: public CBaseEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; +public: + float m_flDelay; + int m_iszKillTarget; +}; + +class CBaseAnimating: public CBaseDelay { +public: + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void HandleAnimEvent(MonsterEvent_t *pEvent) = 0; +public: + // animation needs + float m_flFrameRate; // computed FPS for current sequence + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // last time the event list was checked + BOOL m_fSequenceFinished; // flag set when StudioAdvanceFrame moves across a frame boundry + BOOL m_fSequenceLoops; // true if the sequence loops +}; + +// EHANDLE. Safe way to point to CBaseEntities who may die between frames +class EHANDLE { +public: + edict_t *Get(); + edict_t *Set(edict_t *pent); + + operator int(); + operator CBaseEntity*(); + operator CBasePlayer*(); + + CBaseEntity *operator=(CBaseEntity *pEntity); + CBaseEntity *operator->(); + +private: + edict_t *m_pent; + int m_serialnumber; +}; + +// generic Toggle entity. +class CBaseToggle: public CBaseAnimating { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int GetToggleState() = 0; + virtual float GetDelay() = 0; +public: + TOGGLE_STATE m_toggle_state; + float m_flActivateFinished; // like attack_finished, but for doors + float m_flMoveDistance; // how far a door should slide or rotate + float m_flWait; + float m_flLip; + float m_flTWidth; // for plats + float m_flTLength; // for plats + + Vector m_vecPosition1; + Vector m_vecPosition2; + Vector m_vecAngle1; + Vector m_vecAngle2; + + int m_cTriggersLeft; // trigger_counter only, # of activations remaining + float m_flHeight; + EHANDLE m_hActivator; + void (CBaseToggle::*m_pfnCallWhenMoveDone)(); + Vector m_vecFinalDest; + Vector m_vecFinalAngle; + + int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does + + string_t m_sMaster; // If this button has a master switch, this is the targetname. + // A master switch must be of the multisource type. If all + // of the switches in the multisource have been triggered, then + // the button will be allowed to operate. Otherwise, it will be + // deactivated. +}; + +#include "basemonster.h" +#include "weapons.h" +#include "player.h" + +// Generic Button +class CBaseButton: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; // Buttons that don't take damage can be IMPULSE used +public: + BOOL m_fStayPushed; // button stays pushed in until touched again? + BOOL m_fRotating; // a rotating button? default is a sliding button. + + string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array. + // when this button is touched, it's target entity's TARGET field will be set + // to the button's ChangeTarget. This allows you to make a func_train switch paths, etc. + + locksound_t m_ls; // door lock sounds + + byte m_bLockedSound; // ordinals from entity selection + byte m_bLockedSentence; + byte m_bUnlockedSound; + byte m_bUnlockedSentence; + int m_sounds; +}; + +// MultiSouce + +#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned. +#define MS_MAX_TARGETS 32 + +class CMultiSource: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual BOOL IsTriggered(CBaseEntity *pActivator) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + EHANDLE m_rgEntities[MS_MAX_TARGETS]; + int m_rgTriggered[MS_MAX_TARGETS]; + + int m_iTotal; + string_t m_globalstate; +}; + +// This spawns first when each level begins. +class CWorld: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +}; + +// Inlines +inline edict_t *EHANDLE::Get() +{ + if (!m_pent || m_pent->serialnumber != m_serialnumber) + return NULL; + + return m_pent; +} + +inline edict_t *EHANDLE::Set(edict_t *pent) +{ + m_pent = pent; + if (pent) + m_serialnumber = pent->serialnumber; + + return pent; +} + +inline EHANDLE::operator int() +{ + return Get() != NULL; +} + +inline EHANDLE::operator CBaseEntity *() +{ + return (CBaseEntity *)GET_PRIVATE(Get()); +} + +inline EHANDLE::operator CBasePlayer *() +{ + return static_cast(GET_PRIVATE(Get())); +} + +inline CBaseEntity *EHANDLE::operator=(CBaseEntity *pEntity) +{ + if (pEntity != NULL) + { + m_pent = ENT(pEntity->pev); + if (m_pent) + m_serialnumber = m_pent->serialnumber; + } + else + { + m_pent = NULL; + m_serialnumber = 0; + } + + return pEntity; +} + +inline CBaseEntity *EHANDLE::operator->() +{ + return (CBaseEntity *)GET_PRIVATE(Get()); +} diff --git a/metamod/include/dlls/cdll_dll.h b/metamod/include/dlls/cdll_dll.h new file mode 100644 index 0000000..e69f6fc --- /dev/null +++ b/metamod/include/dlls/cdll_dll.h @@ -0,0 +1,126 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define MAX_WEAPON_SLOTS 5 // hud item selection slots +#define MAX_ITEM_TYPES 6 // hud item selection slots + +#define MAX_ITEMS 4 // hard coded item types + +#define DEFAULT_FOV 90 // the default field of view + +#define HIDEHUD_WEAPONS (1<<0) +#define HIDEHUD_FLASHLIGHT (1<<1) +#define HIDEHUD_ALL (1<<2) +#define HIDEHUD_HEALTH (1<<3) +#define HIDEHUD_TIMER (1<<4) +#define HIDEHUD_MONEY (1<<5) +#define HIDEHUD_CROSSHAIR (1<<6) + +#define STATUSICON_HIDE 0 +#define STATUSICON_SHOW 1 +#define STATUSICON_FLASH 2 + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 +#define HUD_PRINTRADIO 5 + +#define STATUS_NIGHTVISION_ON 1 +#define STATUS_NIGHTVISION_OFF 0 + +#define ITEM_STATUS_NIGHTVISION (1<<0) +#define ITEM_STATUS_DEFUSER (1<<1) + +#define SCORE_STATUS_DEAD (1<<0) +#define SCORE_STATUS_BOMB (1<<1) +#define SCORE_STATUS_VIP (1<<2) + +#define SIGNAL_BUY (1<<0) +#define SIGNAL_BOMB (1<<1) +#define SIGNAL_RESCUE (1<<2) +#define SIGNAL_ESCAPE (1<<3) +#define SIGNAL_VIPSAFETY (1<<4) + +#define DATA_IUSER3_CANSHOOT (1<<0) +#define DATA_IUSER3_FREEZETIMEOVER (1<<1) +#define DATA_IUSER3_INBOMBZONE (1<<2) +#define DATA_IUSER3_HOLDINGSHIELD (1<<3) + +#define MENU_KEY_1 (1<<0) +#define MENU_KEY_2 (1<<1) +#define MENU_KEY_3 (1<<2) +#define MENU_KEY_4 (1<<3) +#define MENU_KEY_5 (1<<4) +#define MENU_KEY_6 (1<<5) +#define MENU_KEY_7 (1<<6) +#define MENU_KEY_8 (1<<7) +#define MENU_KEY_9 (1<<8) +#define MENU_KEY_0 (1<<9) + +#define MAX_AMMO_TYPES 32 // ??? +#define MAX_AMMO_SLOTS 32 // not really slots + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + +#define WEAPON_SUIT 31 +#define WEAPON_ALLWEAPONS (~(1 << WEAPON_SUIT)) + +// custom enum +enum VGUIMenu +{ + VGUI_Menu_Team = 2, + VGUI_Menu_MapBriefing = 4, + + VGUI_Menu_Class_T = 26, + VGUI_Menu_Class_CT, + VGUI_Menu_Buy, + VGUI_Menu_Buy_Pistol, + VGUI_Menu_Buy_ShotGun, + VGUI_Menu_Buy_Rifle, + VGUI_Menu_Buy_SubMachineGun, + VGUI_Menu_Buy_MachineGun, + VGUI_Menu_Buy_Item, +}; + +// custom enum +enum VGUIMenuSlot +{ + VGUI_MenuSlot_Buy_Pistol = 1, + VGUI_MenuSlot_Buy_ShotGun, + VGUI_MenuSlot_Buy_SubMachineGun, + VGUI_MenuSlot_Buy_Rifle, + VGUI_MenuSlot_Buy_MachineGun, + VGUI_MenuSlot_Buy_PrimAmmo, + VGUI_MenuSlot_Buy_SecAmmo, + VGUI_MenuSlot_Buy_Item, +}; diff --git a/metamod/include/dlls/client.h b/metamod/include/dlls/client.h new file mode 100644 index 0000000..f7f8a55 --- /dev/null +++ b/metamod/include/dlls/client.h @@ -0,0 +1,97 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// custom enum +enum ChooseTeamMenuSlot +{ + MENU_SLOT_TEAM_UNDEFINED = -1, + + MENU_SLOT_TEAM_TERRORIST = 1, + MENU_SLOT_TEAM_CT, + MENU_SLOT_TEAM_VIP, + + MENU_SLOT_TEAM_RANDOM = 5, + MENU_SLOT_TEAM_SPECT +}; + +// custom enum +enum BuyItemMenuSlot +{ + MENU_SLOT_ITEM_VEST = 1, + MENU_SLOT_ITEM_VESTHELM, + MENU_SLOT_ITEM_FLASHGREN, + MENU_SLOT_ITEM_HEGREN, + MENU_SLOT_ITEM_SMOKEGREN, + MENU_SLOT_ITEM_NVG, + MENU_SLOT_ITEM_DEFUSEKIT, + MENU_SLOT_ITEM_SHIELD, +}; + +#define CS_NUM_SKIN 4 +#define CZ_NUM_SKIN 5 + +#define FIELD_ORIGIN0 0 +#define FIELD_ORIGIN1 1 +#define FIELD_ORIGIN2 2 + +#define FIELD_ANGLES0 3 +#define FIELD_ANGLES1 4 +#define FIELD_ANGLES2 5 + +#define CUSTOMFIELD_ORIGIN0 0 +#define CUSTOMFIELD_ORIGIN1 1 +#define CUSTOMFIELD_ORIGIN2 2 + +#define CUSTOMFIELD_ANGLES0 3 +#define CUSTOMFIELD_ANGLES1 4 +#define CUSTOMFIELD_ANGLES2 5 + +#define CUSTOMFIELD_SKIN 6 +#define CUSTOMFIELD_SEQUENCE 7 +#define CUSTOMFIELD_ANIMTIME 8 + +typedef struct +{ + float m_fTimeEnteredPVS; + +} ENTITYPVSSTATUS; + +struct PLAYERPVSSTATUS +{ + ENTITYPVSSTATUS m_Status[1380]; + int headnode; + int num_leafs; + short int leafnums[ MAX_ENT_LEAFS ]; +}; + +struct entity_field_alias_t +{ + char name[32]; + int field; +}; diff --git a/metamod/include/dlls/csbot_dll.h b/metamod/include/dlls/csbot_dll.h new file mode 100644 index 0000000..f96b728 --- /dev/null +++ b/metamod/include/dlls/csbot_dll.h @@ -0,0 +1,50 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "../game_shared/GameEvent.h" +#include "../game_shared/bot/bot_util.h" +#include "../game_shared/bot/simple_state_machine.h" +#include "../game_shared/steam_util.h" +#include "../game_shared/perf_counter.h" +#include "../game_shared/bot/bot_manager.h" +#include "../game_shared/bot/bot_constants.h" +#include "../game_shared/bot/bot.h" +#include "../game_shared/shared_util.h" +#include "../game_shared/bot/bot_profile.h" + +#include "../game_shared/bot/improv.h" +#include "../game_shared/bot/nav.h" +#include "../game_shared/bot/nav_node.h" +#include "../game_shared/bot/nav_area.h" +#include "../game_shared/bot/nav_path.h" + +#include "../dlls/hostage/hostage.h" +#include "../dlls/hostage/hostage_localnav.h" + +#include "../dlls/bot/cs_bot.h" diff --git a/metamod/include/dlls/decals.h b/metamod/include/dlls/decals.h new file mode 100644 index 0000000..6f37432 --- /dev/null +++ b/metamod/include/dlls/decals.h @@ -0,0 +1,83 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +enum decal_e +{ + DECAL_GUNSHOT1 = 0, + DECAL_GUNSHOT2, + DECAL_GUNSHOT3, + DECAL_GUNSHOT4, + DECAL_GUNSHOT5, + DECAL_LAMBDA1, + DECAL_LAMBDA2, + DECAL_LAMBDA3, + DECAL_LAMBDA4, + DECAL_LAMBDA5, + DECAL_LAMBDA6, + DECAL_SCORCH1, + DECAL_SCORCH2, + DECAL_BLOOD1, + DECAL_BLOOD2, + DECAL_BLOOD3, + DECAL_BLOOD4, + DECAL_BLOOD5, + DECAL_BLOOD6, + DECAL_YBLOOD1, + DECAL_YBLOOD2, + DECAL_YBLOOD3, + DECAL_YBLOOD4, + DECAL_YBLOOD5, + DECAL_YBLOOD6, + DECAL_GLASSBREAK1, + DECAL_GLASSBREAK2, + DECAL_GLASSBREAK3, + DECAL_BIGSHOT1, + DECAL_BIGSHOT2, + DECAL_BIGSHOT3, + DECAL_BIGSHOT4, + DECAL_BIGSHOT5, + DECAL_SPIT1, + DECAL_SPIT2, + DECAL_BPROOF1, // Bulletproof glass decal + DECAL_GARGSTOMP1, // Gargantua stomp crack + DECAL_SMALLSCORCH1, // Small scorch mark + DECAL_SMALLSCORCH2, // Small scorch mark + DECAL_SMALLSCORCH3, // Small scorch mark + DECAL_MOMMABIRTH, // Big momma birth splatter + DECAL_MOMMASPLAT, +}; + +typedef struct +{ + char *name; + int index; + +} DLL_DECALLIST; + +extern DLL_DECALLIST gDecals[42]; diff --git a/metamod/include/dlls/doors.h b/metamod/include/dlls/doors.h new file mode 100644 index 0000000..92a97b4 --- /dev/null +++ b/metamod/include/dlls/doors.h @@ -0,0 +1,92 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define DOOR_SENTENCEWAIT 6 +#define DOOR_SOUNDWAIT 3 +#define BUTTON_SOUNDWAIT 0.5 + +#define SF_DOOR_ROTATE_Y 0 +#define SF_DOOR_START_OPEN 1 +#define SF_DOOR_ROTATE_BACKWARDS 2 +#define SF_DOOR_PASSABLE 8 +#define SF_DOOR_ONEWAY 16 +#define SF_DOOR_NO_AUTO_RETURN 32 +#define SF_DOOR_ROTATE_Z 64 +#define SF_DOOR_ROTATE_X 128 +#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button. +#define SF_DOOR_NOMONSTERS 512 // Monster can't open +#define SF_DOOR_SILENT 0x80000000 + +class CBaseDoor: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void SetToggleState(int state) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + byte m_bHealthValue; // some doors are medi-kit doors, they give players health + + byte m_bMoveSnd; // sound a door makes while moving + byte m_bStopSnd; // sound a door makes when it stops + + locksound_t m_ls; // door lock sounds + + byte m_bLockedSound; // ordinals from entity selection + byte m_bLockedSentence; + byte m_bUnlockedSound; + byte m_bUnlockedSentence; + + float m_lastBlockedTimestamp; +}; + +class CRotDoor: public CBaseDoor { +public: + virtual void Spawn() = 0; + virtual void Restart() = 0; + virtual void SetToggleState(int state) = 0; +}; + +class CMomentaryDoor: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + byte m_bMoveSnd; // sound a door makes while moving +}; diff --git a/metamod/include/dlls/effects.h b/metamod/include/dlls/effects.h new file mode 100644 index 0000000..5df1335 --- /dev/null +++ b/metamod/include/dlls/effects.h @@ -0,0 +1,407 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_BEAM_STARTON 0x0001 +#define SF_BEAM_TOGGLE 0x0002 +#define SF_BEAM_RANDOM 0x0004 +#define SF_BEAM_RING 0x0008 +#define SF_BEAM_SPARKSTART 0x0010 +#define SF_BEAM_SPARKEND 0x0020 +#define SF_BEAM_DECALS 0x0040 +#define SF_BEAM_SHADEIN 0x0080 +#define SF_BEAM_SHADEOUT 0x0100 +#define SF_BEAM_TEMPORARY 0x8000 + +#define SF_GIBSHOOTER_REPEATABLE 1 +#define SF_FUNNEL_REVERSE 1 + +#define SF_BUBBLES_STARTOFF 0x0001 + +#define SF_BLOOD_RANDOM 0x0001 +#define SF_BLOOD_STREAM 0x0002 +#define SF_BLOOD_PLAYER 0x0004 +#define SF_BLOOD_DECAL 0x0008 + +#define SF_SHAKE_EVERYONE 0x0001 +#define SF_SHAKE_DISRUPT 0x0002 +#define SF_SHAKE_INAIR 0x0004 + +#define SF_FADE_IN 0x0001 +#define SF_FADE_MODULATE 0x0002 +#define SF_FADE_ONLYONE 0x0004 + +#define SF_SPRITE_STARTON 0x0001 +#define SF_SPRITE_ONCE 0x0002 +#define SF_SPRITE_TEMPORARY 0x8000 + +#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out +#define SF_MESSAGE_ALL 0x0002 // Send to all clients + +class CSprite: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + +public: + void SetAttachment(edict_t *pEntity, int attachment) + { + if (pEntity != NULL) + { + pev->skin = ENTINDEX(pEntity); + pev->body = attachment; + pev->aiment = pEntity; + pev->movetype = MOVETYPE_FOLLOW; + } + } + + float Frames() const { return m_maxFrame; } + void SetTransparency(int rendermode, int r, int g, int b, int a, int fx) + { + pev->rendermode = rendermode; + pev->rendercolor.x = r; + pev->rendercolor.y = g; + pev->rendercolor.z = b; + pev->renderamt = a; + pev->renderfx = fx; + } + + void SetTexture(int spriteIndex) { pev->modelindex = spriteIndex; } + void SetScale(float scale) { pev->scale = scale; } + void SetColor(int r, int g, int b) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + void SetBrightness(int brightness) { pev->renderamt = brightness; } + void AnimateAndDie(float framerate) + { + SetThink(&CSprite::AnimateUntilDead); + pev->framerate = framerate; + pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); + pev->nextthink = gpGlobals->time; + } +private: + float m_lastTime; + float m_maxFrame; +}; + +class CBeam: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int ObjectCaps() = 0; + virtual Vector Center() = 0; +public: + void SetType(int type) { pev->rendermode = (pev->rendermode & 0xF0) | (type & 0x0F); } + void SetFlags(int flags) { pev->rendermode = (pev->rendermode & 0x0F) | (flags & 0xF0); } + void SetStartPos(const Vector &pos) { pev->origin = pos; } + void SetEndPos(const Vector &pos) { pev->angles = pos; } + + void SetStartEntity(int entityIndex); + void SetEndEntity(int entityIndex); + + void SetStartAttachment(int attachment) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment & 0xF) << 12); } + void SetEndAttachment(int attachment) { pev->skin = (pev->skin & 0x0FFF) | ((attachment & 0xF) << 12); } + void SetTexture(int spriteIndex) { pev->modelindex = spriteIndex; } + void SetWidth(int width) { pev->scale = width; } + void SetNoise(int amplitude) { pev->body = amplitude; } + void SetColor(int r, int g, int b) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + void SetBrightness(int brightness) { pev->renderamt = brightness; } + void SetFrame(float frame) { pev->frame = frame; } + void SetScrollRate(int speed) { pev->animtime = speed; } + int GetType() const { return pev->rendermode & 0x0F; } + int GetFlags() const { return pev->rendermode & 0xF0; } + int GetStartEntity() const { return pev->sequence & 0xFFF; } + int GetEndEntity() const { return pev->skin & 0xFFF; } + + const Vector &GetStartPos(); + const Vector &GetEndPos(); + + int GetTexture() const { return pev->modelindex; } + int GetWidth() const { return pev->scale; } + int GetNoise() const { return pev->body; } + int GetBrightness() const { return pev->renderamt; } + int GetFrame() const { return pev->frame; } + int GetScrollRate() const { return pev->animtime; } + + void LiveForTime(float time) + { + SetThink(&CBeam::SUB_Remove); + pev->nextthink = gpGlobals->time + time; + } + void BeamDamageInstant(TraceResult *ptr, float damage) + { + pev->dmg = damage; + pev->dmgtime = gpGlobals->time - 1; + BeamDamage(ptr); + } +}; + +class CLaser: public CBeam { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + CSprite *m_pSprite; + int m_iszSpriteName; + Vector m_firePosition; +}; + +class CBubbling: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_density; + int m_frequency; + int m_bubbleModel; + int m_state; +}; + +class CLightning: public CBeam { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Activate() = 0; +public: + inline BOOL ServerSide() const + { + if (!m_life && !(pev->spawnflags & SF_BEAM_RING)) + return TRUE; + + return FALSE; + } +public: + int m_active; + int m_iszStartEntity; + int m_iszEndEntity; + float m_life; + int m_boltWidth; + int m_noiseAmplitude; + int m_brightness; + int m_speed; + float m_restrike; + int m_spriteTexture; + int m_iszSpriteName; + int m_frameStart; + float m_radius; +}; + +class CGlow: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Think() = 0; +public: + float m_lastTime; + float m_maxFrame; +}; + +class CBombGlow: public CSprite { +public: + virtual void Spawn() = 0; + virtual void Think() = 0; +public: + float m_lastTime; + float m_tmBeepPeriod; + bool m_bSetModel; +}; + +class CGibShooter: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual CGib *CreateGib() = 0; +public: + int m_iGibs; + int m_iGibCapacity; + int m_iGibMaterial; + int m_iGibModelIndex; + + float m_flGibVelocity; + float m_flVariance; + float m_flGibLife; +}; + +class CEnvShooter: public CGibShooter { +public: + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual CGib *CreateGib() = 0; +}; + +#define MAX_BEAM 24 + +class CTestEffect: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_iLoop; + int m_iBeam; + + CBeam *m_pBeam[MAX_BEAM]; + + float m_flBeamTime[MAX_BEAM]; + float m_flStartTime; +}; + +class CBlood: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + +public: + int Color() const { return pev->impulse; } + float BloodAmount() const { return pev->dmg; } + + void SetColor(int color) { pev->impulse = color; } + void SetBloodAmount(float amount) { pev->dmg = amount; } +}; + +class CShake: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float Amplitude() const { return pev->scale; } + float Frequency() const { return pev->dmg_save; } + float Duration() const { return pev->dmg_take; } + float Radius() const { return pev->dmg; } + + void SetAmplitude(float amplitude) { pev->scale = amplitude; } + void SetFrequency(float frequency) { pev->dmg_save = frequency; } + void SetDuration(float duration) { pev->dmg_take = duration; } + void SetRadius(float radius) { pev->dmg = radius; } +}; + +class CFade: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float Duration() const { return pev->dmg_take; } + float HoldTime() const { return pev->dmg_save; } + + void SetDuration(float duration) { pev->dmg_take = duration; } + void SetHoldTime(float hold) { pev->dmg_save = hold; } +}; + +class CMessage: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CEnvFunnel: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_iSprite; +}; + +class CEnvBeverage: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CItemSoda: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; +}; + +// Inlines +inline void CBeam::SetStartEntity(int entityIndex) +{ + pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence & 0xF000) << 12); + pev->owner = INDEXENT(entityIndex); +} + +inline void CBeam::SetEndEntity(int entityIndex) +{ + pev->skin = (entityIndex & 0x0FFF) | ((pev->skin & 0xF000) << 12); + pev->aiment = INDEXENT(entityIndex); +} + +inline const Vector &CBeam::GetStartPos() +{ + if (GetType() == BEAM_ENTS) + { + edict_t *pent = INDEXENT(GetStartEntity()); + return pent->v.origin; + } + + return pev->origin; +} + +inline const Vector &CBeam::GetEndPos() +{ + int type = GetType(); + if (type == BEAM_POINTS || type == BEAM_HOSE) + { + return pev->angles; + } + + edict_t *pent = INDEXENT(GetEndEntity()); + if (pent != NULL) + { + return pent->v.origin; + } + + return pev->angles; +} diff --git a/metamod/include/dlls/enginecallback.h b/metamod/include/dlls/enginecallback.h new file mode 100644 index 0000000..dbe3e71 --- /dev/null +++ b/metamod/include/dlls/enginecallback.h @@ -0,0 +1,178 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "event_flags.h" + +// Must be provided by user of this code +extern enginefuncs_t g_engfuncs; + +// The actual engine callbacks +#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) +#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) +#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) +#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) +#define SET_MODEL (*g_engfuncs.pfnSetModel) +#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) +#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) +#define SET_SIZE (*g_engfuncs.pfnSetSize) +#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) +#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) +#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) +#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) +#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) +#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) +#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) +#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) +#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) +#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) +#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) +#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) +#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) +#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor) +#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) +#define WALK_MOVE (*g_engfuncs.pfnWalkMove) +#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) +#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) +#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) +#define TRACE_LINE (*g_engfuncs.pfnTraceLine) +#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) +#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) +#define TRACE_HULL (*g_engfuncs.pfnTraceHull) +#define TRACE_MODEL (*g_engfuncs.pfnTraceModel) +#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) +#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) +#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) +#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) +#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) +#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) +#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) +#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) +#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init) +#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer) +#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte) +#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) +#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) +#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) +#define ADD_SERVER_COMMAND (*g_engfuncs.pfnAddServerCommand) +#define SET_CLIENT_LISTENING (*g_engfuncs.pfnVoice_SetClientListening) +#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) +#define GET_FILE_SIZE (*g_engfuncs.pfnGetFileSize) +#define GET_APPROX_WAVE_PLAY_LEN (*g_engfuncs.pfnGetApproxWavePlayLen) +#define IS_CAREER_MATCH (*g_engfuncs.pfnIsCareerMatch) +#define GET_LOCALIZED_STRING_LENGTH (*g_engfuncs.pfnGetLocalizedStringLength) +#define REGISTER_TUTOR_MESSAGE_SHOWN (*g_engfuncs.pfnRegisterTutorMessageShown) +#define GET_TIMES_TUTOR_MESSAGE_SHOWN (*g_engfuncs.pfnGetTimesTutorMessageShown) +#define ENG_CHECK_PARM (*g_engfuncs.pfnEngCheckParm) + +inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL) { (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); } + +inline void *GET_PRIVATE(edict_t *pent) +{ + if (pent) + return pent->pvPrivateData; + return NULL; +} + +#define MESSAGE_END (*g_engfuncs.pfnMessageEnd) +#define WRITE_BYTE (*g_engfuncs.pfnWriteByte) +#define WRITE_CHAR (*g_engfuncs.pfnWriteChar) +#define WRITE_SHORT (*g_engfuncs.pfnWriteShort) +#define WRITE_LONG (*g_engfuncs.pfnWriteLong) +#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle) +#define WRITE_COORD (*g_engfuncs.pfnWriteCoord) +#define WRITE_STRING (*g_engfuncs.pfnWriteString) +#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) +#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) +#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) +#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) +#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) +#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) +#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) +#define ALERT (*g_engfuncs.pfnAlertMessage) +#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) +#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) +#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) +//#define STRING (*g_engfuncs.pfnSzFromIndex) +#define ALLOC_STRING (*g_engfuncs.pfnAllocString) +#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) +#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) +#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) +#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) +#define FIND_ENTITY_IN_PVS (*g_engfuncs.pfnEntitiesInPVS) +#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) +#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) +#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) +#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) +#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) +#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) +#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) +#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) +#define SERVER_PRINT (*g_engfuncs.pfnServerPrint) +#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) +#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) +#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) +#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) +#define SET_VIEW (*g_engfuncs.pfnSetView) +#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) +#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe) +#define FREE_FILE (*g_engfuncs.pfnFreeFile) +#define END_SECTION (*g_engfuncs.pfnEndSection) +#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) +#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) +#define SET_CLIENT_MAXSPEED (*g_engfuncs.pfnSetClientMaxspeed) +#define CREATE_FAKE_CLIENT (*g_engfuncs.pfnCreateFakeClient) +#define PLAYER_RUN_MOVE (*g_engfuncs.pfnRunPlayerMove) +#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) +#define GET_INFO_BUFFER (*g_engfuncs.pfnGetInfoKeyBuffer) +#define GET_KEY_VALUE (*g_engfuncs.pfnInfoKeyValue) +#define SET_KEY_VALUE (*g_engfuncs.pfnSetKeyValue) +#define SET_CLIENT_KEY_VALUE (*g_engfuncs.pfnSetClientKeyValue) +#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) +#define STATIC_DECAL (*g_engfuncs.pfnStaticDecal) +#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) +#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) +#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) +#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) +#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) +#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) +#define DELTA_SET (*g_engfuncs.pfnDeltaSetField) +#define DELTA_UNSET (*g_engfuncs.pfnDeltaUnsetField) +#define DELTA_ADDENCODER (*g_engfuncs.pfnDeltaAddEncoder) +#define ENGINE_CURRENT_PLAYER (*g_engfuncs.pfnGetCurrentPlayer) +#define ENGINE_CANSKIP (*g_engfuncs.pfnCanSkipPlayer) +#define DELTA_FINDFIELD (*g_engfuncs.pfnDeltaFindField) +#define DELTA_SETBYINDEX (*g_engfuncs.pfnDeltaSetFieldByIndex) +#define DELTA_UNSETBYINDEX (*g_engfuncs.pfnDeltaUnsetFieldByIndex) +#define REMOVE_KEY_VALUE (*g_engfuncs.pfnInfo_RemoveKey) +#define SET_PHYSICS_KEY_VALUE (*g_engfuncs.pfnSetPhysicsKeyValue) +#define ENGINE_GETPHYSINFO (*g_engfuncs.pfnGetPhysicsInfoString) +#define ENGINE_SETGROUPMASK (*g_engfuncs.pfnSetGroupMask) +#define ENGINE_INSTANCE_BASELINE (*g_engfuncs.pfnCreateInstancedBaseline) +#define ENGINE_FORCE_UNMODIFIED (*g_engfuncs.pfnForceUnmodified) +#define PLAYER_CNX_STATS (*g_engfuncs.pfnGetPlayerStats) diff --git a/metamod/include/dlls/explode.h b/metamod/include/dlls/explode.h new file mode 100644 index 0000000..1a2f7a0 --- /dev/null +++ b/metamod/include/dlls/explode.h @@ -0,0 +1,55 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_ENVEXPLOSION_NODAMAGE (1<<0) // when set, ENV_EXPLOSION will not actually inflict damage +#define SF_ENVEXPLOSION_REPEATABLE (1<<1) // can this entity be refired? +#define SF_ENVEXPLOSION_NOFIREBALL (1<<2) // don't draw the fireball +#define SF_ENVEXPLOSION_NOSMOKE (1<<3) // don't draw the smoke +#define SF_ENVEXPLOSION_NODECAL (1<<4) // don't make a scorch mark +#define SF_ENVEXPLOSION_NOSPARKS (1<<5) // don't make a scorch mark + +class CShower: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int ObjectCaps() = 0; + virtual void Think() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +}; + +class CEnvExplosion: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_iMagnitude; + int m_spriteScale; +}; diff --git a/metamod/include/dlls/extdef.h b/metamod/include/dlls/extdef.h new file mode 100644 index 0000000..2135558 --- /dev/null +++ b/metamod/include/dlls/extdef.h @@ -0,0 +1,102 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "regamedll_const.h" + +#ifdef _WIN32 + // Attributes to specify an "exported" function, visible from outside the + // DLL. + #undef DLLEXPORT + #define DLLEXPORT __declspec(dllexport) + // WINAPI should be provided in the windows compiler headers. + // It's usually defined to something like "__stdcall". +#else + #undef DLLEXPORT + #define DLLEXPORT __attribute__((visibility("default"))) + #define WINAPI /* */ +#endif // _WIN32 + +// Simplified macro for declaring/defining exported DLL functions. They +// need to be 'extern "C"' so that the C++ compiler enforces parameter +// type-matching, rather than considering routines with mis-matched +// arguments/types to be overloaded functions... +// +// AFAIK, this is os-independent, but it's included here in osdep.h where +// DLLEXPORT is defined, for convenience. +#define C_DLLEXPORT extern "C" DLLEXPORT + +enum hash_types_e { CLASSNAME }; + +// Things that toggle (buttons/triggers/doors) need this +enum TOGGLE_STATE { TS_AT_TOP, TS_AT_BOTTOM, TS_GOING_UP, TS_GOING_DOWN }; + +typedef struct hash_item_s +{ + entvars_t *pev; + struct hash_item_s *next; + struct hash_item_s *lastHash; + int pevIndex; + +} hash_item_t; + +typedef struct locksounds +{ + string_t sLockedSound; + string_t sLockedSentence; + string_t sUnlockedSound; + string_t sUnlockedSentence; + int iLockedSentence; + int iUnlockedSentence; + float flwaitSound; + float flwaitSentence; + byte bEOFLocked; + byte bEOFUnlocked; + +} locksound_t; + +typedef struct hudtextparms_s +{ + float x; + float y; + int effect; + byte r1,g1,b1,a1; + byte r2,g2,b2,a2; + float fadeinTime; + float fadeoutTime; + float holdTime; + float fxTime; + int channel; + +} hudtextparms_t; + +enum USE_TYPE { USE_OFF, USE_ON, USE_SET, USE_TOGGLE }; +enum TRAIN_CODE { TRAIN_SAFE, TRAIN_BLOCKING, TRAIN_FOLLOWING }; +enum IGNORE_MONSTERS { ignore_monsters = 1, dont_ignore_monsters = 0, missile = 2 }; +enum IGNORE_GLASS { ignore_glass = 1, dont_ignore_glass = 0 }; +enum { point_hull = 0, human_hull = 1, large_hull = 2, head_hull = 3 }; diff --git a/metamod/include/dlls/extdll.h b/metamod/include/dlls/extdll.h new file mode 100644 index 0000000..e81fcd1 --- /dev/null +++ b/metamod/include/dlls/extdll.h @@ -0,0 +1,82 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#pragma warning(disable:4244) // int or float down-conversion +#pragma warning(disable:4305) // int or float data truncation +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4514) // unreferenced inline function removed +#pragma warning(disable:4100) // unreferenced formal parameter + +#include "archtypes.h" +#include "maintypes.h" +#include "regamedll_common.h" + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #define NOWINRES + #define NOSERVICE + #define NOMCX + #define NOIME + #include "winsani_in.h" + #include "windows.h" + #include "winsani_out.h" + #undef PlaySound +#else + #include + #include + #include +#endif // _WIN32 + +// Misc C-runtime library headers +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +// Header file containing definition of globalvars_t and entvars_t +typedef int EOFFSET; // More explicit than "int" +typedef unsigned int func_t; +typedef unsigned int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +// Vector class +#include "vector.h" +//#include "vector.h" +// Defining it as a (bogus) struct helps enforce type-checking +#define vec3_t Vector +// Shared engine/DLL constants + +#include "const.h" +#include "edict.h" + +// Shared header describing protocol between engine and DLLs +#include "eiface.h" +// Shared header between the client DLL and the game DLLs +#include "cdll_dll.h" +#include "extdef.h" diff --git a/metamod/include/dlls/func_break.h b/metamod/include/dlls/func_break.h new file mode 100644 index 0000000..b2f5978 --- /dev/null +++ b/metamod/include/dlls/func_break.h @@ -0,0 +1,119 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// this many shards spawned when breakable objects break; +#define NUM_SHARDS 6 + +// func breakable +#define SF_BREAK_TRIGGER_ONLY 1 // may only be broken by trigger +#define SF_BREAK_TOUCH 2 // can be 'crashed through' by running player (plate glass) +#define SF_BREAK_PRESSURE 4 // can be broken by a player standing on it +#define SF_BREAK_CROWBAR 256 // instant break if hit with crowbar + +// func_pushable (it's also func_breakable, so don't collide with those flags) +#define SF_PUSH_BREAKABLE 128 + +typedef enum +{ + expRandom = 0, + expDirected, + +} Explosions; + +typedef enum +{ + matGlass = 0, + matWood, + matMetal, + matFlesh, + matCinderBlock, + matCeilingTile, + matComputer, + matUnbreakableGlass, + matRocks, + matNone, + matLastMaterial, + +} Materials; + +class CBreakable: public CBaseDelay { +public: + // basic functions + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + + // To spark when hit + virtual void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) = 0; + + // breakables use an overridden takedamage + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + + virtual int DamageDecal(int bitsDamageType) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + +public: + BOOL Explodable() const { return ExplosionMagnitude() > 0; } + int ExplosionMagnitude() const { return pev->impulse; } + void ExplosionSetMagnitude(int magnitude) { pev->impulse = magnitude; } + +public: + Materials m_Material; + Explosions m_Explosion; + int m_idShard; + float m_angle; + int m_iszGibModel; + int m_iszSpawnObject; + float m_flHealth; +}; + +class CPushable: public CBreakable { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0 + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + +public: + float MaxSpeed() const { return m_maxSpeed; } + +public: + int m_lastSound; + float m_maxSpeed; + float m_soundTime; +}; \ No newline at end of file diff --git a/metamod/include/dlls/func_tank.h b/metamod/include/dlls/func_tank.h new file mode 100644 index 0000000..6ae26fa --- /dev/null +++ b/metamod/include/dlls/func_tank.h @@ -0,0 +1,159 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_TANK_ACTIVE 0x0001 +#define SF_TANK_PLAYER 0x0002 +#define SF_TANK_HUMANS 0x0004 +#define SF_TANK_ALIENS 0x0008 +#define SF_TANK_LINEOFSIGHT 0x0010 +#define SF_TANK_CANCONTROL 0x0020 +#define SF_TANK_SOUNDON 0x8000 + +enum TANKBULLET +{ + TANK_BULLET_NONE = 0, // Custom damage + TANK_BULLET_9MM, // env_laser (duration is 0.5 rate of fire) + TANK_BULLET_MP5, // rockets + TANK_BULLET_12MM, // explosion? +}; + +class CFuncTank: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + + // Bmodels don't go across transitions + virtual int ObjectCaps() = 0; + virtual BOOL OnControls(entvars_t *pevTest) = 0; + virtual void Think() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void Fire(const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker) = 0; + virtual Vector UpdateTargetPosition(CBaseEntity *pTarget) = 0; +public: + BOOL IsActive() const { return (pev->spawnflags & SF_TANK_ACTIVE) == SF_TANK_ACTIVE; } + void TankActivate() + { + pev->spawnflags |= SF_TANK_ACTIVE; + pev->nextthink = pev->ltime + 0.1f; + m_fireLast = 0.0f; + } + void TankDeactivate() + { + pev->spawnflags &= ~SF_TANK_ACTIVE; + m_fireLast = 0.0f; + StopRotSound(); + } + + BOOL CanFire() const { return (gpGlobals->time - m_lastSightTime) < m_persist; } + Vector BarrelPosition() + { + Vector forward, right, up; + UTIL_MakeVectorsPrivate(pev->angles, forward, right, up); + return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); + } +protected: + CBasePlayer *m_pController; + float m_flNextAttack; + Vector m_vecControllerUsePos; + + float m_yawCenter; // "Center" yaw + float m_yawRate; // Max turn rate to track targets + float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) + // Zero is full rotation + + float m_yawTolerance; // Tolerance angle + + float m_pitchCenter; // "Center" pitch + float m_pitchRate; // Max turn rate on pitch + float m_pitchRange; // Range of pitch motion as above + float m_pitchTolerance; // Tolerance angle + + float m_fireLast; // Last time I fired + float m_fireRate; // How many rounds/second + float m_lastSightTime; // Last time I saw target + float m_persist; // Persistence of firing (how long do I shoot when I can't see) + float m_minRange; // Minimum range to aim/track + float m_maxRange; // Max range to aim/track + + Vector m_barrelPos; // Length of the freakin barrel + float m_spriteScale; // Scale of any sprites we shoot + int m_iszSpriteSmoke; + int m_iszSpriteFlash; + TANKBULLET m_bulletType; // Bullet type + int m_iBulletDamage; // 0 means use Bullet type's default damage + + Vector m_sightOrigin; // Last sight of target + int m_spread; // firing spread + int m_iszMaster; // Master entity (game_team_master or multisource) +}; + +class CFuncTankGun: public CFuncTank { +public: + virtual void Fire(const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker) = 0; +}; + +class CFuncTankLaser: public CFuncTank { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Activate() = 0; + virtual void Think() = 0; + virtual void Fire(const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker) = 0; +private: + CLaser *m_pLaser; + float m_laserTime; +}; + +class CFuncTankRocket: public CFuncTank { +public: + virtual void Precache() = 0; + virtual void Fire(const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker) = 0; +}; + +class CFuncTankMortar: public CFuncTank { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Fire(const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker) = 0; +}; + +class CFuncTankControls: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Think() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + CFuncTank *m_pTank; +}; diff --git a/metamod/include/dlls/gamerules.h b/metamod/include/dlls/gamerules.h new file mode 100644 index 0000000..cce267d --- /dev/null +++ b/metamod/include/dlls/gamerules.h @@ -0,0 +1,678 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "voice_gamemgr.h" + +#define MAX_RULE_BUFFER 1024 +#define MAX_VOTE_MAPS 100 +#define MAX_VIP_QUEUES 5 + +#define MAX_BOMB_RADIUS 2048 + +#define MAP_VIP_SAFETYZONE_UNINITIALIZED 0 // uninitialized +#define MAP_HAVE_VIP_SAFETYZONE_YES 1 // has VIP safety zone +#define MAP_HAVE_VIP_SAFETYZONE_NO 2 // does not have VIP safetyzone + +#define MAP_HAS_CAMERAS_INIT 2 // initial +#define MAP_HAS_CAMERAS_YES 1 // on map have of camera's + +#define ITEM_RESPAWN_TIME 30 +#define WEAPON_RESPAWN_TIME 20 +#define AMMO_RESPAWN_TIME 20 + +// longest the intermission can last, in seconds +#define MAX_INTERMISSION_TIME 120 + +// when we are within this close to running out of entities, items +// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn +#define ENTITY_INTOLERANCE 100 + +#define MAX_MOTD_CHUNK 60 +#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) + +// custom enum +#define WINNER_NONE 0 +#define WINNER_DRAW 1 + +enum +{ + WINSTATUS_CTS = 1, + WINSTATUS_TERRORISTS, + WINSTATUS_DRAW, +}; + +// custom enum +// used for EndRoundMessage() logged messages +enum ScenarioEventEndRound +{ + ROUND_NONE, + ROUND_TARGET_BOMB, + ROUND_VIP_ESCAPED, + ROUND_VIP_ASSASSINATED, + ROUND_TERRORISTS_ESCAPED, + ROUND_CTS_PREVENT_ESCAPE, + ROUND_ESCAPING_TERRORISTS_NEUTRALIZED, + ROUND_BOMB_DEFUSED, + ROUND_CTS_WIN, + ROUND_TERRORISTS_WIN, + ROUND_END_DRAW, + ROUND_ALL_HOSTAGES_RESCUED, + ROUND_TARGET_SAVED, + ROUND_HOSTAGE_NOT_RESCUED, + ROUND_TERRORISTS_NOT_ESCAPED, + ROUND_VIP_NOT_ESCAPED, + ROUND_GAME_COMMENCE, +}; + +enum RewardRules +{ + RR_CTS_WIN, + RR_TERRORISTS_WIN, + RR_TARGET_BOMB, + RR_VIP_ESCAPED, + RR_VIP_ASSASSINATED, + RR_TERRORISTS_ESCAPED, + RR_CTS_PREVENT_ESCAPE, + RR_ESCAPING_TERRORISTS_NEUTRALIZED, + RR_BOMB_DEFUSED, + RR_BOMB_PLANTED, + RR_BOMB_EXPLODED, + RR_ALL_HOSTAGES_RESCUED, + RR_TARGET_BOMB_SAVED, + RR_HOSTAGE_NOT_RESCUED, + RR_VIP_NOT_ESCAPED, + RR_LOSER_BONUS_DEFAULT, + RR_LOSER_BONUS_MIN, + RR_LOSER_BONUS_MAX, + RR_LOSER_BONUS_ADD, + RR_RESCUED_HOSTAGE, + RR_TOOK_HOSTAGE_ACC, + RR_TOOK_HOSTAGE, + RR_END +}; + +// custom enum +enum RewardAccount +{ + REWARD_TARGET_BOMB = 3500, + REWARD_VIP_ESCAPED = 3500, + REWARD_VIP_ASSASSINATED = 3250, + REWARD_TERRORISTS_ESCAPED = 3150, + REWARD_CTS_PREVENT_ESCAPE = 3500, + REWARD_ESCAPING_TERRORISTS_NEUTRALIZED = 3250, + REWARD_BOMB_DEFUSED = 3250, + REWARD_BOMB_PLANTED = 800, + REWARD_BOMB_EXPLODED = 3250, + REWARD_CTS_WIN = 3000, + REWARD_TERRORISTS_WIN = 3000, + REWARD_ALL_HOSTAGES_RESCUED = 2500, + + // the end round was by the expiration time + REWARD_TARGET_BOMB_SAVED = 3250, + REWARD_HOSTAGE_NOT_RESCUED = 3250, + REWARD_VIP_NOT_ESCAPED = 3250, + + // loser bonus + REWARD_LOSER_BONUS_DEFAULT = 1400, + REWARD_LOSER_BONUS_MIN = 1500, + REWARD_LOSER_BONUS_MAX = 3000, + REWARD_LOSER_BONUS_ADD = 500, + + REWARD_RESCUED_HOSTAGE = 750, + REWARD_KILLED_ENEMY = 300, + REWARD_KILLED_VIP = 2500, + REWARD_VIP_HAVE_SELF_RESCUED = 2500, + + REWARD_TAKEN_HOSTAGE = 1000 + +}; + +// custom enum +enum PaybackForBadThing +{ + PAYBACK_FOR_KILLED_TEAMMATES = -3300, +}; + +// custom enum +enum InfoMapBuyParam +{ + BUYING_EVERYONE = 0, + BUYING_ONLY_CTS, + BUYING_ONLY_TERRORISTS, + BUYING_NO_ONE, +}; + +// weapon respawning return codes +enum +{ + GR_NONE = 0, + + GR_WEAPON_RESPAWN_YES, + GR_WEAPON_RESPAWN_NO, + + GR_AMMO_RESPAWN_YES, + GR_AMMO_RESPAWN_NO, + + GR_ITEM_RESPAWN_YES, + GR_ITEM_RESPAWN_NO, + + GR_PLR_DROP_GUN_ALL, + GR_PLR_DROP_GUN_ACTIVE, + GR_PLR_DROP_GUN_NO, + + GR_PLR_DROP_AMMO_ALL, + GR_PLR_DROP_AMMO_ACTIVE, + GR_PLR_DROP_AMMO_NO, +}; + +// custom enum +enum +{ + SCENARIO_BLOCK_TIME_EXPRIRED = (1 << 0), + SCENARIO_BLOCK_NEED_PLAYERS = (1 << 1), + SCENARIO_BLOCK_VIP_ESCAPRE = (1 << 2), + SCENARIO_BLOCK_PRISON_ESCAPRE = (1 << 3), + SCENARIO_BLOCK_BOMB = (1 << 4), + SCENARIO_BLOCK_TEAM_EXTERMINATION = (1 << 5), + SCENARIO_BLOCK_HOSTAGE_RESCUE = (1 << 6), +}; + +// Player relationship return codes +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; + +class CItem; + +class CGameRules { +protected: + virtual ~CGameRules() {}; +public: + virtual void RefreshSkillData() = 0; // fill skill data struct with proper values + virtual void Think() = 0; // runs every server frame, should handle any timer tasks, periodic events, etc. + virtual BOOL IsAllowedToSpawn(CBaseEntity *pEntity) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). + + virtual BOOL FAllowFlashlight() = 0; // Are players allowed to switch on their flashlight? + virtual BOOL FShouldSwitchWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; // should the player switch to this weapon? + virtual BOOL GetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) = 0; // I can't use this weapon anymore, get me the next best one. + + // Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer() = 0; // is this a multiplayer game? (either coop or deathmatch) + virtual BOOL IsDeathmatch() = 0; // is this a deathmatch game? + virtual BOOL IsTeamplay() = 0; // is this deathmatch game being played with team rules? + virtual BOOL IsCoOp() = 0; // is this a coop game? + virtual const char *GetGameDescription() = 0; // this is the game name that gets seen in the server browser + + // Client connection/disconnection + virtual BOOL ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *szRejectReason) = 0; // a client just connected to the server (player hasn't spawned yet) + virtual void InitHUD(CBasePlayer *pl) = 0; // the client dll is ready for updating + virtual void ClientDisconnected(edict_t *pClient) = 0; // a client just disconnected from the server + virtual void UpdateGameMode(CBasePlayer *pPlayer) = 0; // the client needs to be informed of the current game mode + + // Client damage rules + virtual float FlPlayerFallDamage(CBasePlayer *pPlayer) = 0; + virtual BOOL FPlayerCanTakeDamage(CBasePlayer *pPlayer, CBaseEntity *pAttacker) = 0; // can this player take damage from this attacker? + virtual BOOL ShouldAutoAim(CBasePlayer *pPlayer, edict_t *target) = 0; + + // Client spawn/respawn control + virtual void PlayerSpawn(CBasePlayer *pPlayer) = 0; // called by CBasePlayer::Spawn just before releasing player into the game + virtual void PlayerThink(CBasePlayer *pPlayer) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted + virtual BOOL FPlayerCanRespawn(CBasePlayer *pPlayer) = 0; // is this player allowed to respawn now? + virtual float FlPlayerSpawnTime(CBasePlayer *pPlayer) = 0; // When in the future will this player be able to spawn? + virtual edict_t *GetPlayerSpawnSpot(CBasePlayer *pPlayer) = 0; // Place this player on their spawnspot and face them the proper direction. + + virtual BOOL AllowAutoTargetCrosshair() = 0; + virtual BOOL ClientCommand_DeadOrAlive(CBasePlayer *pPlayer, const char *pcmd) = 0; + virtual BOOL ClientCommand(CBasePlayer *pPlayer, const char *pcmd) = 0; // handles the user commands; returns TRUE if command handled properly + virtual void ClientUserInfoChanged(CBasePlayer *pPlayer, char *infobuffer) = 0; // the player has changed userinfo; can change it now + + // Client kills/scoring + virtual int IPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled) = 0; // how many points do I award whoever kills this player? + virtual void PlayerKilled(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; // Called each time a player dies + virtual void DeathNotice(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor) = 0; // Call this from within a GameRules class to report an obituary. + + // Weapon retrieval + virtual BOOL CanHavePlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pItem) = 0; // The player is touching an CBasePlayerItem, do I give it to him? + virtual void PlayerGotWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; // Called each time a player picks up a weapon from the ground + + // Weapon spawn/respawn control + virtual int WeaponShouldRespawn(CBasePlayerItem *pWeapon) = 0; // should this weapon respawn? + virtual float FlWeaponRespawnTime(CBasePlayerItem *pWeapon) = 0; // when may this weapon respawn? + virtual float FlWeaponTryRespawn(CBasePlayerItem *pWeapon) = 0; // can i respawn now, and if not, when should i try again? + virtual Vector VecWeaponRespawnSpot(CBasePlayerItem *pWeapon) = 0; // where in the world should this weapon respawn? + + // Item retrieval + virtual BOOL CanHaveItem(CBasePlayer *pPlayer, CItem *pItem) = 0; // is this player allowed to take this item? + virtual void PlayerGotItem(CBasePlayer *pPlayer, CItem *pItem) = 0; // call each time a player picks up an item (battery, healthkit, longjump) + + // Item spawn/respawn control + virtual int ItemShouldRespawn(CItem *pItem) = 0; // Should this item respawn? + virtual float FlItemRespawnTime(CItem *pItem) = 0; // when may this item respawn? + virtual Vector VecItemRespawnSpot(CItem *pItem) = 0; // where in the world should this item respawn? + + // Ammo retrieval + virtual BOOL CanHaveAmmo(CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry) = 0; // can this player take more of this ammo? + virtual void PlayerGotAmmo(CBasePlayer *pPlayer, char *szName, int iCount) = 0; // called each time a player picks up some ammo in the world + + // Ammo spawn/respawn control + virtual int AmmoShouldRespawn(CBasePlayerAmmo *pAmmo) = 0; // should this ammo item respawn? + virtual float FlAmmoRespawnTime(CBasePlayerAmmo *pAmmo) = 0; // when should this ammo item respawn? + virtual Vector VecAmmoRespawnSpot(CBasePlayerAmmo *pAmmo) = 0; // where in the world should this ammo item respawn? + + // Healthcharger respawn control + virtual float FlHealthChargerRechargeTime() = 0; // how long until a depleted HealthCharger recharges itself? + virtual float FlHEVChargerRechargeTime() = 0; // how long until a depleted HealthCharger recharges itself? + + // What happens to a dead player's weapons + virtual int DeadPlayerWeapons(CBasePlayer *pPlayer) = 0; // what do I do with a player's weapons when he's killed? + + // What happens to a dead player's ammo + virtual int DeadPlayerAmmo(CBasePlayer *pPlayer) = 0; // Do I drop ammo when the player dies? How much? + + // Teamplay stuff + virtual const char *GetTeamID(CBaseEntity *pEntity) = 0; // what team is this entity on? + virtual int PlayerRelationship(CBasePlayer *pPlayer, CBaseEntity *pTarget) = 0; // What is the player's relationship with this entity? + virtual int GetTeamIndex(const char *pTeamName) = 0; + virtual const char *GetIndexedTeamName(int teamIndex) = 0; + virtual BOOL IsValidTeam(const char *pTeamName) = 0; + virtual void ChangePlayerTeam(CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib) = 0; + virtual const char *SetDefaultPlayerTeam(CBasePlayer *pPlayer) = 0; + + // Sounds + virtual BOOL PlayTextureSounds() = 0; + + // Monsters + virtual BOOL FAllowMonsters() = 0; // are monsters allowed + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame() = 0; + + // Stuff that is shared between client and server. + virtual BOOL IsFreezePeriod() = 0; + virtual void ServerDeactivate() = 0; + virtual void CheckMapConditions() = 0; +public: + BOOL m_bFreezePeriod; + BOOL m_bBombDropped; + + // custom + char *m_GameDesc; +}; + +// CHalfLifeRules - rules for the single player Half-Life game. +class CHalfLifeRules: public CGameRules { +protected: + virtual ~CHalfLifeRules() {}; +public: + virtual void Think() = 0; + virtual BOOL IsAllowedToSpawn(CBaseEntity *pEntity) = 0; + virtual BOOL FAllowFlashlight() = 0; + + virtual BOOL FShouldSwitchWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; + virtual BOOL GetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) = 0; + + // Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer() = 0; + virtual BOOL IsDeathmatch() = 0; + virtual BOOL IsCoOp() = 0; + + // Client connection/disconnection + virtual BOOL ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) = 0; + virtual void InitHUD(CBasePlayer *pl) = 0; // the client dll is ready for updating + virtual void ClientDisconnected(edict_t *pClient) = 0; + + // Client damage rules + virtual float FlPlayerFallDamage(CBasePlayer *pPlayer) = 0; + + // Client spawn/respawn control + virtual void PlayerSpawn(CBasePlayer *pPlayer) = 0; + virtual void PlayerThink(CBasePlayer *pPlayer) = 0; + virtual BOOL FPlayerCanRespawn(CBasePlayer *pPlayer) = 0; + virtual float FlPlayerSpawnTime(CBasePlayer *pPlayer) = 0; + virtual edict_t *GetPlayerSpawnSpot(CBasePlayer *pPlayer) = 0; + + virtual BOOL AllowAutoTargetCrosshair() = 0; + + // Client kills/scoring + virtual int IPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled) = 0; + virtual void PlayerKilled(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; + virtual void DeathNotice(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; + + // Weapon retrieval + virtual void PlayerGotWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; + + // Weapon spawn/respawn control + virtual int WeaponShouldRespawn(CBasePlayerItem *pWeapon) = 0; + virtual float FlWeaponRespawnTime(CBasePlayerItem *pWeapon) = 0; + virtual float FlWeaponTryRespawn(CBasePlayerItem *pWeapon) = 0; + virtual Vector VecWeaponRespawnSpot(CBasePlayerItem *pWeapon) = 0; + + // Item retrieval + virtual BOOL CanHaveItem(CBasePlayer *pPlayer, CItem *pItem) = 0; + virtual void PlayerGotItem(CBasePlayer *pPlayer, CItem *pItem) = 0; + + // Item spawn/respawn control + virtual int ItemShouldRespawn(CItem *pItem) = 0; + virtual float FlItemRespawnTime(CItem *pItem) = 0; + virtual Vector VecItemRespawnSpot(CItem *pItem) = 0; + + // Ammo retrieval + virtual void PlayerGotAmmo(CBasePlayer *pPlayer, char *szName, int iCount) = 0; + + // Ammo spawn/respawn control + virtual int AmmoShouldRespawn(CBasePlayerAmmo *pAmmo) = 0; + virtual float FlAmmoRespawnTime(CBasePlayerAmmo *pAmmo) = 0; + virtual Vector VecAmmoRespawnSpot(CBasePlayerAmmo *pAmmo) = 0; + + // Healthcharger respawn control + virtual float FlHealthChargerRechargeTime() = 0; + + // What happens to a dead player's weapons + virtual int DeadPlayerWeapons(CBasePlayer *pPlayer) = 0; + + // What happens to a dead player's ammo + virtual int DeadPlayerAmmo(CBasePlayer *pPlayer) = 0; + + // Teamplay stuff + virtual const char *GetTeamID(CBaseEntity *pEntity) = 0; + virtual int PlayerRelationship(CBasePlayer *pPlayer, CBaseEntity *pTarget) = 0; + + // Monsters + virtual BOOL FAllowMonsters() = 0; +}; + +// CHalfLifeMultiplay - rules for the basic half life multiplayer competition +class CHalfLifeMultiplay: public CGameRules { +protected: + virtual ~CHalfLifeMultiplay() {}; +public: + virtual void RefreshSkillData() = 0; + virtual void Think() = 0; + virtual BOOL IsAllowedToSpawn(CBaseEntity *pEntity) = 0; + virtual BOOL FAllowFlashlight() = 0; + + virtual BOOL FShouldSwitchWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; + virtual BOOL GetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) = 0; + + virtual BOOL IsMultiplayer() = 0; + virtual BOOL IsDeathmatch() = 0; + virtual BOOL IsCoOp() = 0; + + // Client connection/disconnection + // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in szRejectReason + // Only the client's name and remote address are provided to the dll for verification. + virtual BOOL ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128]) = 0; + virtual void InitHUD(CBasePlayer *pl) = 0; + virtual void ClientDisconnected(edict_t *pClient) = 0; + virtual void UpdateGameMode(CBasePlayer *pPlayer) = 0; + + // Client damage rules + virtual float FlPlayerFallDamage(CBasePlayer *pPlayer) = 0; + virtual BOOL FPlayerCanTakeDamage(CBasePlayer *pPlayer, CBaseEntity *pAttacker) = 0; + + // Client spawn/respawn control + virtual void PlayerSpawn(CBasePlayer *pPlayer) = 0; + virtual void PlayerThink(CBasePlayer *pPlayer) = 0; + virtual BOOL FPlayerCanRespawn(CBasePlayer *pPlayer) = 0; + virtual float FlPlayerSpawnTime(CBasePlayer *pPlayer) = 0; + virtual edict_t *GetPlayerSpawnSpot(CBasePlayer *pPlayer) = 0; + + virtual BOOL AllowAutoTargetCrosshair() = 0; + + virtual BOOL ClientCommand_DeadOrAlive(CBasePlayer *pPlayer, const char *pcmd) = 0; + virtual BOOL ClientCommand(CBasePlayer *pPlayer, const char *pcmd) = 0; + virtual void ClientUserInfoChanged(CBasePlayer *pPlayer, char *infobuffer) = 0; + + // Client kills/scoring + virtual int IPointsForKill(CBasePlayer *pAttacker, CBasePlayer *pKilled) = 0; + virtual void PlayerKilled(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; + virtual void DeathNotice(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; + + // Weapon retrieval + virtual BOOL CanHavePlayerItem(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; + virtual void PlayerGotWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pWeapon) = 0; + + // Weapon spawn/respawn control + virtual int WeaponShouldRespawn(CBasePlayerItem *pWeapon) = 0; + virtual float FlWeaponRespawnTime(CBasePlayerItem *pWeapon) = 0; + virtual float FlWeaponTryRespawn(CBasePlayerItem *pWeapon) = 0; + virtual Vector VecWeaponRespawnSpot(CBasePlayerItem *pWeapon) = 0; + + // Item retrieval + virtual BOOL CanHaveItem(CBasePlayer *pPlayer, CItem *pItem) = 0; + virtual void PlayerGotItem(CBasePlayer *pPlayer, CItem *pItem) = 0; + + // Item spawn/respawn control + virtual int ItemShouldRespawn(CItem *pItem) = 0; + virtual float FlItemRespawnTime(CItem *pItem) = 0; + virtual Vector VecItemRespawnSpot(CItem *pItem) = 0; + + // Ammo retrieval + virtual void PlayerGotAmmo(CBasePlayer *pPlayer, char *szName, int iCount) = 0; + + // Ammo spawn/respawn control + virtual int AmmoShouldRespawn(CBasePlayerAmmo *pAmmo) = 0; + virtual float FlAmmoRespawnTime(CBasePlayerAmmo *pAmmo) = 0; + virtual Vector VecAmmoRespawnSpot(CBasePlayerAmmo *pAmmo) = 0; + + // Healthcharger respawn control + virtual float FlHealthChargerRechargeTime() = 0; + virtual float FlHEVChargerRechargeTime() = 0; + + // What happens to a dead player's weapons + virtual int DeadPlayerWeapons(CBasePlayer *pPlayer) = 0; + + // What happens to a dead player's ammo + virtual int DeadPlayerAmmo(CBasePlayer *pPlayer) = 0; + + // Teamplay stuff + virtual const char *GetTeamID(CBaseEntity *pEntity) = 0; + virtual int PlayerRelationship(CBasePlayer *pPlayer, CBaseEntity *pTarget) = 0; + + virtual BOOL PlayTextureSounds() = 0; + + // Monsters + virtual BOOL FAllowMonsters() = 0; + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame() = 0; + virtual void ServerDeactivate() = 0; + virtual void CheckMapConditions() = 0; + + // Recreate all the map entities from the map data (preserving their indices), + // then remove everything else except the players. + // Also get rid of all world decals. + virtual void CleanUpMap() = 0; + + virtual void RestartRound() = 0; + + // check if the scenario has been won/lost + virtual void CheckWinConditions() = 0; + virtual void RemoveGuns() = 0; + virtual void GiveC4() = 0; + virtual void ChangeLevel() = 0; + virtual void GoToIntermission() = 0; + + // Setup counts for m_iNumTerrorist, m_iNumCT, m_iNumSpawnableTerrorist, m_iNumSpawnableCT, etc. + virtual void InitializePlayerCounts(int &NumAliveTerrorist, int &NumAliveCT, int &NumDeadTerrorist, int &NumDeadCT) = 0; + + virtual void BalanceTeams() = 0; + virtual void SwapAllPlayers() = 0; + virtual void UpdateTeamScores() = 0; + virtual void EndRoundMessage(const char *sentence, int event) = 0; + virtual void SetAccountRules(RewardRules rules, int amount) = 0; + virtual RewardAccount GetAccountRules(RewardRules rules) const = 0; + + // BOMB MAP FUNCTIONS + virtual BOOL IsThereABomber() = 0; + virtual BOOL IsThereABomb() = 0; + virtual TeamName SelectDefaultTeam() = 0; + + virtual bool HasRoundTimeExpired() = 0; + virtual bool IsBombPlanted() = 0; + +public: + bool ShouldSkipShowMenu() const { return m_bSkipShowMenu; } + void MarkShowMenuSkipped() { m_bSkipShowMenu = false; } + + bool ShouldSkipSpawn() const { return m_bSkipSpawn; } + void MarkSpawnSkipped() { m_bSkipSpawn = false; } + + float TimeRemaining() { return m_iRoundTimeSecs - gpGlobals->time + m_fRoundCount; } + bool IsMatchStarted() { return (m_fTeamCount != 0.0f || m_fCareerRoundMenuTime != 0.0f || m_fCareerMatchMenuTime != 0.0f); } + + inline void TerminateRound(float tmDelay, int iWinStatus) + { + m_iRoundWinStatus = iWinStatus; + m_fTeamCount = gpGlobals->time + tmDelay; + m_bRoundTerminating = true; + } +public: + CVoiceGameMgr m_VoiceGameMgr; + float m_fTeamCount; // m_flRestartRoundTime, the global time when the round is supposed to end, if this is not 0 + float m_flCheckWinConditions; + float m_fRoundCount; + int m_iRoundTime; // (From mp_roundtime) - How many seconds long this round is. + int m_iRoundTimeSecs; + int m_iIntroRoundTime; // (From mp_freezetime) - How many seconds long the intro round (when players are frozen) is. + float m_fIntroRoundCount; // The global time when the intro round ends and the real one starts + // wrote the original "m_flRoundTime" comment for this variable). + int m_iAccountTerrorist; + int m_iAccountCT; + int m_iNumTerrorist; // The number of terrorists on the team (this is generated at the end of a round) + int m_iNumCT; // The number of CTs on the team (this is generated at the end of a round) + int m_iNumSpawnableTerrorist; + int m_iNumSpawnableCT; + int m_iSpawnPointCount_Terrorist; // Number of Terrorist spawn points + int m_iSpawnPointCount_CT; // Number of CT spawn points + int m_iHostagesRescued; + int m_iHostagesTouched; + int m_iRoundWinStatus; // 1 == CT's won last round, 2 == Terrorists did, 3 == Draw, no winner + + short m_iNumCTWins; + short m_iNumTerroristWins; + + bool m_bTargetBombed; // whether or not the bomb has been bombed + bool m_bBombDefused; // whether or not the bomb has been defused + + bool m_bMapHasBombTarget; + bool m_bMapHasBombZone; + bool m_bMapHasBuyZone; + bool m_bMapHasRescueZone; + bool m_bMapHasEscapeZone; + + int m_iMapHasVIPSafetyZone; // 0 = uninitialized; 1 = has VIP safety zone; 2 = DOES not have VIP safetyzone + int m_bMapHasCameras; + int m_iC4Timer; + int m_iC4Guy; // The current Terrorist who has the C4. + int m_iLoserBonus; // the amount of money the losing team gets. This scales up as they lose more rounds in a row + int m_iNumConsecutiveCTLoses; // the number of rounds the CTs have lost in a row. + int m_iNumConsecutiveTerroristLoses; // the number of rounds the Terrorists have lost in a row. + + float m_fMaxIdlePeriod; // For the idle kick functionality. This is tha max amount of time that the player has to be idle before being kicked + + int m_iLimitTeams; + bool m_bLevelInitialized; + bool m_bRoundTerminating; + bool m_bCompleteReset; // Set to TRUE to have the scores reset next time round restarts + float m_flRequiredEscapeRatio; + int m_iNumEscapers; + int m_iHaveEscaped; + bool m_bCTCantBuy; + bool m_bTCantBuy; // Who can and can't buy. + float m_flBombRadius; + int m_iConsecutiveVIP; + int m_iTotalGunCount; + int m_iTotalGrenadeCount; + int m_iTotalArmourCount; + int m_iUnBalancedRounds; // keeps track of the # of consecutive rounds that have gone by where one team outnumbers the other team by more than 2 + int m_iNumEscapeRounds; // keeps track of the # of consecutive rounds of escape played.. Teams will be swapped after 8 rounds + int m_iMapVotes[MAX_VOTE_MAPS]; + int m_iLastPick; + int m_iMaxMapTime; + int m_iMaxRounds; + int m_iTotalRoundsPlayed; + int m_iMaxRoundsWon; + int m_iStoredSpectValue; + float m_flForceCameraValue; + float m_flForceChaseCamValue; + float m_flFadeToBlackValue; + CBasePlayer *m_pVIP; + CBasePlayer *m_pVIPQueue[MAX_VIP_QUEUES]; + float m_flIntermissionEndTime; + float m_flIntermissionStartTime; + BOOL m_iEndIntermissionButtonHit; + float m_tmNextPeriodicThink; + bool m_bFirstConnected; + bool m_bInCareerGame; + float m_fCareerRoundMenuTime; + int m_iCareerMatchWins; + int m_iRoundWinDifference; + float m_fCareerMatchMenuTime; + bool m_bSkipSpawn; + + // custom + bool m_bSkipShowMenu; + bool m_bNeededPlayers; + float m_flEscapeRatio; +}; + +typedef struct mapcycle_item_s +{ + struct mapcycle_item_s *next; + char mapname[32]; + int minplayers; + int maxplayers; + char rulebuffer[MAX_RULE_BUFFER]; + +} mapcycle_item_t; + +typedef struct mapcycle_s +{ + struct mapcycle_item_s *items; + struct mapcycle_item_s *next_item; + +} mapcycle_t; + +class CCStrikeGameMgrHelper: public IVoiceGameMgrHelper { +public: + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pSender) = 0; +}; + +extern CGameRules *g_pGameRules; + +inline CHalfLifeMultiplay *CSGameRules() +{ + return reinterpret_cast(g_pGameRules); +} diff --git a/metamod/include/dlls/h_battery.h b/metamod/include/dlls/h_battery.h new file mode 100644 index 0000000..e523dd6 --- /dev/null +++ b/metamod/include/dlls/h_battery.h @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CRecharge: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float m_flNextCharge; + int m_iReactivate; + int m_iJuice; + int m_iOn; + float m_flSoundTime; +}; diff --git a/metamod/include/dlls/h_cycler.h b/metamod/include/dlls/h_cycler.h new file mode 100644 index 0000000..5f9ab00 --- /dev/null +++ b/metamod/include/dlls/h_cycler.h @@ -0,0 +1,104 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CCycler: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + + // Don't treat as a live target + virtual BOOL IsAlive() = 0; + virtual void Think() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int m_animate; +}; + +// we should get rid of all the other cyclers and replace them with this. +class CGenericCycler: public CCycler { +public: + virtual void Spawn() = 0; +}; + +// Probe droid imported for tech demo compatibility +class CCyclerProbe: public CCycler { +public: + virtual void Spawn() = 0; +}; + +class CCyclerSprite: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Restart() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual void Think() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + inline int ShouldAnimate() { return (m_animate && m_maxFrame > 1.0f); } +public: + int m_animate; + float m_lastTime; + float m_maxFrame; + int m_renderfx; + int m_rendermode; + float m_renderamt; + vec3_t m_rendercolor; +}; + +class CWeaponCycler: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal = 0) = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; +public: + int m_iszModel; + int m_iModel; +}; + +// Flaming Wreakage +class CWreckage: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Think() = 0; +public: + int m_flStartTime; +}; diff --git a/metamod/include/dlls/healthkit.h b/metamod/include/dlls/healthkit.h new file mode 100644 index 0000000..eb4e63d --- /dev/null +++ b/metamod/include/dlls/healthkit.h @@ -0,0 +1,52 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CHealthKit: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CWallHealth: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float m_flNextCharge; + int m_iReactivate; + int m_iJuice; + int m_iOn; + float m_flSoundTime; +}; diff --git a/metamod/include/dlls/hintmessage.h b/metamod/include/dlls/hintmessage.h new file mode 100644 index 0000000..ce63fde --- /dev/null +++ b/metamod/include/dlls/hintmessage.h @@ -0,0 +1,81 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "utlvector.h" + +#define DHF_ROUND_STARTED (1<<1) +#define DHF_HOSTAGE_SEEN_FAR (1<<2) +#define DHF_HOSTAGE_SEEN_NEAR (1<<3) +#define DHF_HOSTAGE_USED (1<<4) +#define DHF_HOSTAGE_INJURED (1<<5) +#define DHF_HOSTAGE_KILLED (1<<6) +#define DHF_FRIEND_SEEN (1<<7) +#define DHF_ENEMY_SEEN (1<<8) +#define DHF_FRIEND_INJURED (1<<9) +#define DHF_FRIEND_KILLED (1<<10) +#define DHF_ENEMY_KILLED (1<<11) +#define DHF_BOMB_RETRIEVED (1<<12) +#define DHF_AMMO_EXHAUSTED (1<<15) +#define DHF_IN_TARGET_ZONE (1<<16) +#define DHF_IN_RESCUE_ZONE (1<<17) +#define DHF_IN_ESCAPE_ZONE (1<<18) +#define DHF_IN_VIPSAFETY_ZONE (1<<19) +#define DHF_NIGHTVISION (1<<20) +#define DHF_HOSTAGE_CTMOVE (1<<21) +#define DHF_SPEC_DUCK (1<<22) + +#define DHM_ROUND_CLEAR (DHF_ROUND_STARTED | DHF_HOSTAGE_KILLED | DHF_FRIEND_KILLED | DHF_BOMB_RETRIEVED) +#define DHM_CONNECT_CLEAR (DHF_HOSTAGE_SEEN_FAR | DHF_HOSTAGE_SEEN_NEAR | DHF_HOSTAGE_USED | DHF_HOSTAGE_INJURED | DHF_FRIEND_SEEN | DHF_ENEMY_SEEN | DHF_FRIEND_INJURED | DHF_ENEMY_KILLED | DHF_AMMO_EXHAUSTED | DHF_IN_TARGET_ZONE | DHF_IN_RESCUE_ZONE | DHF_IN_ESCAPE_ZONE | DHF_IN_VIPSAFETY_ZONE | DHF_HOSTAGE_CTMOVE | DHF_SPEC_DUCK) + +class CHintMessage { +public: + CHintMessage(const char *hintString, bool isHint, CUtlVector *args, float duration); + ~CHintMessage(); +public: + float GetDuration() const { return m_duration; } + void Send(CBaseEntity *client); + +private: + const char *m_hintString; + bool m_isHint; + CUtlVector m_args; + float m_duration; +}; + +class CHintMessageQueue { +public: + void Reset(); + void Update(CBaseEntity *client); + bool AddMessage(const char *message, float duration, bool isHint, CUtlVector *args); + bool IsEmpty() const { return m_messages.Count() == 0; } + +private: + float m_tmMessageEnd; + CUtlVector m_messages; +}; diff --git a/metamod/include/dlls/hookchains.h b/metamod/include/dlls/hookchains.h new file mode 100644 index 0000000..408d8a4 --- /dev/null +++ b/metamod/include/dlls/hookchains.h @@ -0,0 +1,110 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +template +class IHookChain { +protected: + virtual ~IHookChain() {} + +public: + virtual t_ret callNext(t_args... args) = 0; + virtual t_ret callOriginal(t_args... args) = 0; +}; + +template +class IHookChainClass { +protected: + virtual ~IHookChainClass() {} + +public: + virtual t_ret callNext(t_class *, t_args... args) = 0; + virtual t_ret callOriginal(t_class *, t_args... args) = 0; +}; + +template +class IVoidHookChain +{ +protected: + virtual ~IVoidHookChain() {} + +public: + virtual void callNext(t_args... args) = 0; + virtual void callOriginal(t_args... args) = 0; +}; + +template +class IVoidHookChainClass +{ +protected: + virtual ~IVoidHookChainClass() {} + +public: + virtual void callNext(t_class *, t_args... args) = 0; + virtual void callOriginal(t_class *, t_args... args) = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IHookChainRegistry { +public: + typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; + virtual void unregisterHook(hookfunc_t hook) = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IHookChainRegistryClass { +public: + typedef t_ret(*hookfunc_t)(IHookChainClass*, t_class *, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; + virtual void unregisterHook(hookfunc_t hook) = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IVoidHookChainRegistry { +public: + typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; + virtual void unregisterHook(hookfunc_t hook) = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IVoidHookChainRegistryClass { +public: + typedef void(*hookfunc_t)(IVoidHookChainClass*, t_class *, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; + virtual void unregisterHook(hookfunc_t hook) = 0; +}; diff --git a/metamod/include/dlls/hostage/hostage.h b/metamod/include/dlls/hostage/hostage.h new file mode 100644 index 0000000..2819339 --- /dev/null +++ b/metamod/include/dlls/hostage/hostage.h @@ -0,0 +1,232 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// Improved the hostages from CZero +#include "hostage/hostage_improv.h" + +#define MAX_NODES 100 +#define MAX_HOSTAGES 12 +#define MAX_HOSTAGES_NAV 20 + +#define HOSTAGE_STEPSIZE 26.0f +#define HOSTAGE_STEPSIZE_DEFAULT 18.0f + +#define VEC_HOSTAGE_VIEW Vector(0, 0, 12) +#define VEC_HOSTAGE_HULL_MIN Vector(-10, -10, 0) +#define VEC_HOSTAGE_HULL_MAX Vector(10, 10, 62) + +#define VEC_HOSTAGE_CROUCH Vector(10, 10, 30) +#define RESCUE_HOSTAGES_RADIUS 256.0f // rescue zones from legacy info_* + +class CHostage; +class CLocalNav; +class CHostageImprov; +class CHostageManager; + +enum HostageChatterType +{ + HOSTAGE_CHATTER_START_FOLLOW = 0, + HOSTAGE_CHATTER_STOP_FOLLOW, + HOSTAGE_CHATTER_INTIMIDATED, + HOSTAGE_CHATTER_PAIN, + HOSTAGE_CHATTER_SCARED_OF_GUNFIRE, + HOSTAGE_CHATTER_SCARED_OF_MURDER, + HOSTAGE_CHATTER_LOOK_OUT, + HOSTAGE_CHATTER_PLEASE_RESCUE_ME, + HOSTAGE_CHATTER_SEE_RESCUE_ZONE, + HOSTAGE_CHATTER_IMPATIENT_FOR_RESCUE, + HOSTAGE_CHATTER_CTS_WIN , + HOSTAGE_CHATTER_TERRORISTS_WIN, + HOSTAGE_CHATTER_RESCUED, + HOSTAGE_CHATTER_WARN_NEARBY, + HOSTAGE_CHATTER_WARN_SPOTTED, + HOSTAGE_CHATTER_CALL_TO_RESCUER, + HOSTAGE_CHATTER_RETREAT, + HOSTAGE_CHATTER_COUGH, + HOSTAGE_CHATTER_BLINDED, + HOSTAGE_CHATTER_SAW_HE_GRENADE, + HOSTAGE_CHATTER_DEATH_CRY, + NUM_HOSTAGE_CHATTER_TYPES, +}; + +extern CHostageManager *g_pHostages; +extern int g_iHostageNumber; + +// A Counter-Strike Hostage Simple +class CHostage: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int ObjectCaps() = 0; // make hostage "useable" + virtual int Classify() = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual int BloodColor() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int GetActivity() { return m_Activity; } + + // queries + bool IsFollowingSomeone() { return IsFollowing(); } + CBaseEntity *GetLeader() // return our leader, or NULL + { + if (m_improv != NULL) + { + return m_improv->GetFollowLeader(); + } + + return m_hTargetEnt; + } + bool IsFollowing(const CBaseEntity *entity = NULL) + { + if (m_improv != NULL) + { + return m_improv->IsFollowing(); + } + + if (entity == NULL && m_hTargetEnt == NULL || (entity != NULL && m_hTargetEnt != entity)) + return false; + + if (m_State != FOLLOW) + return false; + + return true; + } + bool IsValid() { return (pev->takedamage == DAMAGE_YES); } + bool IsDead() { return (pev->deadflag == DEAD_DEAD); } + bool IsAtHome() { return (pev->origin - m_vStart).IsLengthGreaterThan(20) != true; } + const Vector *GetHomePosition() { return &m_vStart; } +public: + int m_Activity; + BOOL m_bTouched; + BOOL m_bRescueMe; + float m_flFlinchTime; + float m_flNextChange; + float m_flMarkPosition; + int m_iModel; + int m_iSkin; + float m_flNextRadarTime; + enum state { FOLLOW, STAND, DUCK, SCARED, IDLE, FOLLOWPATH } + m_State; + Vector m_vStart; + Vector m_vStartAngles; + Vector m_vPathToFollow[20]; + int m_iWaypoint; + CBasePlayer *m_target; + CLocalNav *m_LocalNav; + int nTargetNode; + Vector vecNodes[MAX_NODES]; + EHANDLE m_hStoppedTargetEnt; + float m_flNextFullThink; + float m_flPathCheckInterval; + float m_flLastPathCheck; + int m_nPathNodes; + BOOL m_fHasPath; + float m_flPathAcquired; + Vector m_vOldPos; + int m_iHostageIndex; + BOOL m_bStuck; + float m_flStuckTime; + CHostageImprov *m_improv; + + enum ModelType { REGULAR_GUY, OLD_GUY, BLACK_GUY, GOOFY_GUY } + m_whichModel; +}; + +class SimpleChatter { +public: + struct SoundFile + { + char *filename; + float duration; + }; + + struct ChatterSet + { + SoundFile file[32]; + int count; + int index; + bool needsShuffle; + }; +private: + ChatterSet m_chatter[21]; +}; + +class CHostageManager { +public: + SimpleChatter *GetChatter() + { + return &m_chatter; + } + // Iterate over all active hostages in the game, invoking functor on each. + // If functor returns false, stop iteration and return false. + template + inline bool ForEachHostage(Functor &func) const + { + for (int i = 0; i < m_hostageCount; i++) + { + CHostage *hostage = m_hostage[i]; + + if (hostage == NULL || hostage->pev->deadflag == DEAD_DEAD) + continue; + + if (func(hostage) == false) + return false; + } + + return true; + } + inline CHostage *GetClosestHostage(const Vector &pos, float *resultRange = NULL) + { + float range; + float closeRange = 1e8f; + CHostage *close = NULL; + + for (int i = 0; i < m_hostageCount; i++) + { + range = (m_hostage[i]->pev->origin - pos).Length(); + + if (range < closeRange) + { + closeRange = range; + close = m_hostage[i]; + } + } + + if (resultRange) + *resultRange = closeRange; + + return close; + } + +private: + CHostage *m_hostage[MAX_HOSTAGES]; + int m_hostageCount; + SimpleChatter m_chatter; +}; diff --git a/metamod/include/dlls/hostage/hostage_improv.h b/metamod/include/dlls/hostage/hostage_improv.h new file mode 100644 index 0000000..9ec69a7 --- /dev/null +++ b/metamod/include/dlls/hostage/hostage_improv.h @@ -0,0 +1,331 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "hostage/hostage.h" +#include "hostage/hostage_states.h" + +class CHostage; +enum HostageChatterType; + +// A Counter-Strike Hostage improved +class CHostageImprov: public CImprov { +public: + // invoked when an improv reaches its MoveTo goal + virtual void OnMoveToSuccess(const Vector &goal) = 0; + + // invoked when an improv fails to reach a MoveTo goal + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) = 0; + virtual void OnInjury(float amount) = 0; + virtual bool IsAlive() const = 0; + virtual void MoveTo(const Vector &goal) = 0; + virtual void LookAt(const Vector &target) = 0; + virtual void ClearLookAt() = 0; + virtual void FaceTo(const Vector &goal) = 0; + virtual void ClearFaceTo() = 0; + virtual bool IsAtMoveGoal(float error = 20.0f) const = 0; + virtual bool HasLookAt() const = 0; + virtual bool HasFaceTo() const = 0; + virtual bool IsAtFaceGoal() const = 0; + virtual bool IsFriendInTheWay(const Vector &goalPos) const = 0; + virtual bool IsFriendInTheWay(CBaseEntity *myFriend, const Vector &goalPos) const = 0; + virtual void MoveForward() = 0; + virtual void MoveBackward() = 0; + virtual void StrafeLeft() = 0; + virtual void StrafeRight() = 0; + + #define HOSTAGE_MUST_JUMP true + virtual bool Jump() = 0; + + virtual void Crouch() = 0; + virtual void StandUp() = 0; + virtual void TrackPath(const Vector &pathGoal, float deltaT) = 0; // move along path by following "pathGoal" + virtual void StartLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos) = 0; + virtual bool TraverseLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT) = 0; + virtual bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal = NULL) = 0; + virtual void Run() = 0; + virtual void Walk() = 0; + virtual void Stop() = 0; + virtual float GetMoveAngle() const = 0; + virtual float GetFaceAngle() const = 0; + virtual const Vector &GetFeet() const = 0; + virtual const Vector &GetCentroid() const = 0; + virtual const Vector &GetEyes() const = 0; + virtual bool IsRunning() const = 0; + virtual bool IsWalking() const = 0; + virtual bool IsStopped() const = 0; + virtual bool IsCrouching() const = 0; + virtual bool IsJumping() const = 0; + virtual bool IsUsingLadder() const = 0; + virtual bool IsOnGround() const = 0; + virtual bool IsMoving() const = 0; + virtual bool CanRun() const = 0; + virtual bool CanCrouch() const = 0; + virtual bool CanJump() const = 0; + virtual bool IsVisible(const Vector &pos, bool testFOV = false) const = 0; // return true if hostage can see position + virtual bool IsPlayerLookingAtMe(CBasePlayer *other, float cosTolerance = 0.95f) const = 0; + virtual CBasePlayer *IsAnyPlayerLookingAtMe(int team = 0, float cosTolerance = 0.95f) const = 0; + virtual CBasePlayer *GetClosestPlayerByTravelDistance(int team = 0, float *range = NULL) const = 0; + virtual CNavArea *GetLastKnownArea() const = 0; + virtual void OnUpdate(float deltaT) = 0; + virtual void OnUpkeep(float deltaT) = 0; + virtual void OnReset() = 0; + virtual void OnGameEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) = 0; + virtual void OnTouch(CBaseEntity *other) = 0; // in contact with "other" +public: + enum MoveType { Stopped, Walking, Running }; + enum ScareType { NERVOUS, SCARED, TERRIFIED }; + + const Vector &GetKnownGoodPosition() const { return m_knownGoodPos; } + void ApplyForce(Vector force) { m_vel.x += force.x; m_vel.y += force.y; } // apply a force to the hostage + const Vector GetActualVelocity() const { return m_actualVel; } + void SetMoveLimit(MoveType limit) { m_moveLimit = limit; } + MoveType GetMoveLimit() const { return m_moveLimit; } + CNavPath *GetPath() { return &m_path; } + + // hostage states + // stand idle + void Idle() { m_behavior.SetState(&m_idleState); } + bool IsIdle() const { return m_behavior.IsState(&m_idleState); } + + // begin following "leader" + void Follow(CBasePlayer *leader) { m_followState.SetLeader(leader); m_behavior.SetState(&m_followState); } + bool IsFollowing(const CBaseEntity *leader = NULL) const { return m_behavior.IsState(&m_followState); } + + // Escape + void Escape() { m_behavior.SetState(&m_escapeState); } + bool IsEscaping() const { return m_behavior.IsState(&m_escapeState); } + + // Retreat + void Retreat() { m_behavior.SetState(&m_retreatState); } + bool IsRetreating() const { return m_behavior.IsState(&m_retreatState); } + + CBaseEntity *GetFollowLeader() const { return m_followState.GetLeader(); } + ScareType GetScareIntensity() const { return m_scareIntensity; } + bool IsIgnoringTerrorists() const { return m_ignoreTerroristTimer.IsElapsed(); } + float GetAggression() const { return m_aggression; } + bool IsTalking() const { return m_talkingTimer.IsElapsed(); } + CHostage *GetEntity() const { return m_hostage; } + void SetMoveAngle(float angle) { m_moveAngle = angle; } +public: + CountdownTimer m_coughTimer; + CountdownTimer m_grenadeTimer; +private: + CHostage *m_hostage; + CNavArea *m_lastKnownArea; // last area we were in + mutable Vector m_centroid; + mutable Vector m_eye; + HostageStateMachine m_behavior; + HostageIdleState m_idleState; + HostageEscapeState m_escapeState; + HostageRetreatState m_retreatState; + HostageFollowState m_followState; + HostageAnimateState m_animateState; + bool m_didFidget; + float m_aggression; + IntervalTimer m_lastSawCT; + IntervalTimer m_lastSawT; + CountdownTimer m_checkNearbyTerroristTimer; + bool m_isTerroristNearby; + CountdownTimer m_nearbyTerroristTimer; + CountdownTimer m_scaredTimer; + ScareType m_scareIntensity; + CountdownTimer m_ignoreTerroristTimer; + CountdownTimer m_blinkTimer; + char m_blinkCounter; + IntervalTimer m_lastInjuryTimer; + IntervalTimer m_lastNoiseTimer; + mutable CountdownTimer m_avoidFriendTimer; + mutable bool m_isFriendInTheWay; + CountdownTimer m_chatterTimer; + bool m_isDelayedChatterPending; + CountdownTimer m_delayedChatterTimer; + HostageChatterType m_delayedChatterType; + bool m_delayedChatterMustSpeak; + CountdownTimer m_talkingTimer; + unsigned int m_moveFlags; + Vector2D m_vel; + Vector m_actualVel; + Vector m_moveGoal; + Vector m_knownGoodPos; + bool m_hasKnownGoodPos; + Vector m_priorKnownGoodPos; + bool m_hasPriorKnownGoodPos; + CountdownTimer m_priorKnownGoodPosTimer; + IntervalTimer m_collisionTimer; + Vector m_viewGoal; + bool m_isLookingAt; + Vector m_faceGoal; + bool m_isFacingTo; + CNavPath m_path; // current path to follow + CNavPathFollower m_follower; + Vector m_lastPosition; + MoveType m_moveType; + MoveType m_moveLimit; + bool m_isCrouching; // true if hostage is crouching + CountdownTimer m_minCrouchTimer; + float m_moveAngle; + NavRelativeDirType m_wiggleDirection; + + CountdownTimer m_wiggleTimer; // for wiggling + CountdownTimer m_wiggleJumpTimer; + CountdownTimer m_inhibitObstacleAvoidance; + CountdownTimer m_jumpTimer; // if zero, we can jump + + bool m_hasJumped; + bool m_hasJumpedIntoAir; + Vector m_jumpTarget; + CountdownTimer m_clearPathTimer; + bool m_traversingLadder; + EHANDLE m_visiblePlayer[MAX_CLIENTS]; + int m_visiblePlayerCount; + CountdownTimer m_visionTimer; +}; + +class CheckWayFunctor { +public: + CheckWayFunctor(const CHostageImprov *me, const Vector &goalPos) + { + m_me = me; + m_goalPos = goalPos; + m_blocker = NULL; + } + bool operator()(CHostage *them) + { + if (((CBaseMonster *)them)->IsAlive() && m_me->IsFriendInTheWay((CBaseEntity *)them, m_goalPos)) + { + m_blocker = them; + return false; + } + + return true; + } + + const CHostageImprov *m_me; + Vector m_goalPos; + CHostage *m_blocker; +}; + +// Functor used with NavAreaBuildPath() for building Hostage paths. +// Once we hook up crouching and ladders, this can be removed and ShortestPathCost() can be used instead. +class HostagePathCost { +public: + float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder) + { + if (fromArea == NULL) + { + // first area in path, no cost + return 0.0f; + } + else + { + // compute distance travelled along path so far + float dist; + + if (ladder != NULL) + { + const float ladderCost = 10.0f; + return ladder->m_length * ladderCost + fromArea->GetCostSoFar(); + } + else + { + dist = (*area->GetCenter() - *fromArea->GetCenter()).Length(); + } + + float cost = dist + fromArea->GetCostSoFar(); + + // if this is a "crouch" area, add penalty + if (area->GetAttributes() & NAV_CROUCH) + { + const float crouchPenalty = 10.0f; + cost += crouchPenalty * dist; + } + + // if this is a "jump" area, add penalty + if (area->GetAttributes() & NAV_JUMP) + { + const float jumpPenalty = 10.0f; + cost += jumpPenalty * dist; + } + + return cost; + } + } +}; + +class KeepPersonalSpace { +public: + KeepPersonalSpace(CHostageImprov *improv) + { + m_improv = improv; + m_velDir = improv->GetActualVelocity(); + m_speed = m_velDir.NormalizeInPlace(); + } + bool operator()(CBaseEntity *entity) + { + const float space = 1.0f; + Vector to; + float range; + + if (entity == reinterpret_cast(m_improv->GetEntity())) + return true; + + if (entity->IsPlayer() && !entity->IsAlive()) + return true; + + to = entity->pev->origin - m_improv->GetCentroid(); + range = to.NormalizeInPlace(); + + CBasePlayer *player = static_cast(entity); + + const float spring = 50.0f; + const float damper = 1.0f; + + if (range >= spring) + return true; + + const float cosTolerance = 0.8f; + if (entity->IsPlayer() && player->m_iTeam == CT && !m_improv->IsFollowing() && m_improv->IsPlayerLookingAtMe(player, cosTolerance)) + return true; + + const float minSpace = (spring - range); + float ds = -minSpace; + + m_improv->ApplyForce(to * ds); + + const float force = 0.1f; + m_improv->ApplyForce(m_speed * -force * m_velDir); + + return true; + } + +private: + CHostageImprov *m_improv; + Vector m_velDir; + float m_speed; +}; diff --git a/metamod/include/dlls/hostage/hostage_localnav.h b/metamod/include/dlls/hostage/hostage_localnav.h new file mode 100644 index 0000000..5a40e6f --- /dev/null +++ b/metamod/include/dlls/hostage/hostage_localnav.h @@ -0,0 +1,58 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define NODE_INVALID_EMPTY -1 + +#define PATH_TRAVERSABLE_EMPTY 0 +#define PATH_TRAVERSABLE_SLOPE 1 +#define PATH_TRAVERSABLE_STEP 2 +#define PATH_TRAVERSABLE_STEPJUMPABLE 3 + +typedef int node_index_t; + +typedef struct localnode_s +{ + Vector vecLoc; + int offsetX; + int offsetY; + byte bDepth; + BOOL fSearched; + node_index_t nindexParent; + +} localnode_t; + +class CLocalNav { +private: + CHostage *m_pOwner; + edict_t *m_pTargetEnt; + BOOL m_fTargetEntHit; + localnode_t *m_nodeArr; + node_index_t m_nindexAvailableNode; + Vector m_vecStartingLoc; +}; diff --git a/metamod/include/dlls/hostage/hostage_states.h b/metamod/include/dlls/hostage/hostage_states.h new file mode 100644 index 0000000..9ac99cf --- /dev/null +++ b/metamod/include/dlls/hostage/hostage_states.h @@ -0,0 +1,203 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CHostageImprov; + +class HostageState: public SimpleState, public IImprovEvent { +public: + virtual ~HostageState() {} + virtual void UpdateStationaryAnimation(CHostageImprov *improv) {} +}; + +class HostageStateMachine: public SimpleStateMachine, public IImprovEvent { +public: + virtual void OnMoveToSuccess(const Vector &goal) {} + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) {} + virtual void OnInjury(float amount) {} +}; + +class HostageIdleState: public HostageState { +public: + virtual ~HostageIdleState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Idle"; } + virtual void UpdateStationaryAnimation(CHostageImprov *improv) {} + virtual void OnMoveToSuccess(const Vector &goal) {} + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) {} + virtual void OnInjury(float amount = -1.0f) {} +private: + CountdownTimer m_waveTimer; + CountdownTimer m_fleeTimer; + CountdownTimer m_disagreeTimer; + CountdownTimer m_escapeTimer; + CountdownTimer m_askTimer; + IntervalTimer m_intimidatedTimer; + CountdownTimer m_pleadTimer; + + enum + { + NotMoving = 0, + Moving, + MoveDone, + MoveFailed, + } m_moveState; + + bool m_mustFlee; +}; + +class HostageEscapeToCoverState: public HostageState { +public: + virtual ~HostageEscapeToCoverState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Escape:ToCover"; } + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) {} +public: + void SetRescueGoal(const Vector &rescueGoal) { m_rescueGoal = rescueGoal; } + +private: + Vector m_rescueGoal; + Vector m_spot; + bool m_canEscape; +}; + +class HostageEscapeLookAroundState: public HostageState { +public: + virtual ~HostageEscapeLookAroundState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Escape:LookAround"; } + +private: + CountdownTimer m_timer; +}; + +class HostageEscapeState: public HostageState { +public: + virtual ~HostageEscapeState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Escape"; } + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) {} +public: + void ToCover() { m_behavior.SetState(&m_toCoverState); } + void LookAround() { m_behavior.SetState(&m_lookAroundState); } +private: + HostageEscapeToCoverState m_toCoverState; + HostageEscapeLookAroundState m_lookAroundState; + HostageStateMachine m_behavior; + bool m_canEscape; + CountdownTimer m_runTimer; +}; + +class HostageRetreatState: public HostageState { +public: + virtual ~HostageRetreatState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Retreat"; } +}; + +class HostageFollowState: public HostageState { +public: + virtual ~HostageFollowState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Follow"; } + virtual void UpdateStationaryAnimation(CHostageImprov *improv) {} +public: + void SetLeader(CBaseEntity *leader) { m_leader = leader; } + CBaseEntity *GetLeader() const { return m_leader; } +private: + mutable EHANDLE m_leader; + Vector m_lastLeaderPos; + bool m_isWaiting; + float m_stopRange; + CountdownTimer m_makeWayTimer; + CountdownTimer m_impatientTimer; + CountdownTimer m_repathTimer; + bool m_isWaitingForFriend; + CountdownTimer m_waitForFriendTimer; +}; + +class HostageAnimateState: public HostageState { +public: + virtual ~HostageAnimateState() {} + virtual void OnEnter(CHostageImprov *improv) {} + virtual void OnUpdate(CHostageImprov *improv) {} + virtual void OnExit(CHostageImprov *improv) {} + virtual const char *GetName() const { return "Animate"; } +public: + struct SeqInfo + { + int seqID; + float holdTime; + float rate; + }; + + enum PerformanceType + { + None = 0, + Walk, + Run, + Jump, + Fall, + Crouch, + CrouchWalk, + Calm, + Anxious, + Afraid, + Sitting, + GettingUp, + Waving, + LookingAround, + Disagreeing, + Flinching, + }; + + bool IsBusy() const { return (m_sequenceCount > 0); } + int GetCurrentSequenceID() { return m_currentSequence; } + PerformanceType GetPerformance() const { return m_performance; } + void SetPerformance(PerformanceType performance) { m_performance = performance; } +private: + enum { MAX_SEQUENCES = 8 }; + struct SeqInfo m_sequence[MAX_SEQUENCES]; + int m_sequenceCount; + int m_currentSequence; + enum PerformanceType m_performance; + bool m_isHolding; + CountdownTimer m_holdTimer; +}; diff --git a/metamod/include/dlls/items.h b/metamod/include/dlls/items.h new file mode 100644 index 0000000..e485295 --- /dev/null +++ b/metamod/include/dlls/items.h @@ -0,0 +1,155 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +enum ItemRestType +{ + ITEM_TYPE_BUYING, // when a player buying items + ITEM_TYPE_TOUCHED, // when the player touches with a weaponbox or armoury_entity + ITEM_TYPE_EQUIPPED // when a entity game_player_equip gives item to player or default item's on player spawn +}; + +// constant items +#define ITEM_ID_ANTIDOTE 2 +#define ITEM_ID_SECURITY 3 + +enum ItemID +{ + ITEM_NONE = -1, + ITEM_SHIELDGUN, + ITEM_P228, + ITEM_GLOCK, + ITEM_SCOUT, + ITEM_HEGRENADE, + ITEM_XM1014, + ITEM_C4, + ITEM_MAC10, + ITEM_AUG, + ITEM_SMOKEGRENADE, + ITEM_ELITE, + ITEM_FIVESEVEN, + ITEM_UMP45, + ITEM_SG550, + ITEM_GALIL, + ITEM_FAMAS, + ITEM_USP, + ITEM_GLOCK18, + ITEM_AWP, + ITEM_MP5N, + ITEM_M249, + ITEM_M3, + ITEM_M4A1, + ITEM_TMP, + ITEM_G3SG1, + ITEM_FLASHBANG, + ITEM_DEAGLE, + ITEM_SG552, + ITEM_AK47, + ITEM_KNIFE, + ITEM_P90, + ITEM_NVG, + ITEM_DEFUSEKIT, + ITEM_KEVLAR, + ITEM_ASSAULT, + ITEM_LONGJUMP, + ITEM_SODACAN, + ITEM_HEALTHKIT, + ITEM_ANTIDOTE, + ITEM_BATTERY +}; + +class CItem: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual CBaseEntity *Respawn() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CWorldItem: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +public: + int m_iType; +}; + +class CItemSuit: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemBattery: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemAntidote: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemSecurity: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemLongJump: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemKevlar: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemAssaultSuit: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; + +class CItemThighPack: public CItem { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual BOOL MyTouch(CBasePlayer *pPlayer) = 0; +}; diff --git a/metamod/include/dlls/lights.h b/metamod/include/dlls/lights.h new file mode 100644 index 0000000..df0fb68 --- /dev/null +++ b/metamod/include/dlls/lights.h @@ -0,0 +1,50 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_LIGHT_START_OFF 1 + +class CLight: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +private: + int m_iStyle; + int m_iszPattern; + BOOL m_iStartedOff; +}; + +class CEnvLight: public CLight { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +}; diff --git a/metamod/include/dlls/mapinfo.h b/metamod/include/dlls/mapinfo.h new file mode 100644 index 0000000..8e3c2de --- /dev/null +++ b/metamod/include/dlls/mapinfo.h @@ -0,0 +1,40 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class CMapInfo: public CPointEntity +{ +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + +public: + InfoMapBuyParam m_iBuyingStatus; + float m_flBombRadius; +}; diff --git a/metamod/include/dlls/maprules.h b/metamod/include/dlls/maprules.h new file mode 100644 index 0000000..dde173e --- /dev/null +++ b/metamod/include/dlls/maprules.h @@ -0,0 +1,236 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define MAX_EQUIP 32 +#define SF_SCORE_NEGATIVE 0x0001 +#define SF_SCORE_TEAM 0x0002 + +#define SF_ENVTEXT_ALLPLAYERS 0x0001 + +#define SF_TEAMMASTER_FIREONCE 0x0001 +#define SF_TEAMMASTER_ANYTEAM 0x0002 + +#define SF_TEAMSET_FIREONCE 0x0001 +#define SF_TEAMSET_CLEARTEAM 0x0002 + +#define SF_PKILL_FIREONCE 0x0001 + +#define SF_GAMECOUNT_FIREONCE 0x0001 +#define SF_GAMECOUNT_RESET 0x0002 + +#define SF_GAMECOUNTSET_FIREONCE 0x0001 + +#define SF_PLAYEREQUIP_USEONLY 0x0001 + +#define SF_PTEAM_FIREONCE 0x0001 +#define SF_PTEAM_KILL 0x0002 +#define SF_PTEAM_GIB 0x0004 + +class CRuleEntity: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; +public: + void SetMaster(int iszMaster) { m_iszMaster = iszMaster; } + +private: + string_t m_iszMaster; +}; + +// CRulePointEntity -- base class for all rule "point" entities (not brushes) +class CRulePointEntity: public CRuleEntity { +public: + virtual void Spawn() = 0; +}; + +// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) +// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing +class CRuleBrushEntity: public CRuleEntity { +public: + virtual void Spawn() = 0; +}; + +// CGameScore / game_score -- award points to player / team +// Points +/- total +// Flag: Allow negative scores SF_SCORE_NEGATIVE +// Flag: Award points to team in teamplay SF_SCORE_TEAM +class CGameScore: public CRulePointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + int Points() const { return int(pev->frags); } + BOOL AllowNegativeScore() { return pev->spawnflags & SF_SCORE_NEGATIVE; } + BOOL AwardToTeam() const { return pev->spawnflags & SF_SCORE_TEAM; } + void SetPoints(int points) { pev->frags = points; } +}; + +// CGameEnd / game_end -- Ends the game in MP +class CGameEnd: public CRulePointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) +// Flag: All players SF_ENVTEXT_ALLPLAYERS +class CGameText: public CRulePointEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + +public: + BOOL MessageToAll() const { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS) == SF_ENVTEXT_ALLPLAYERS; } + void MessageSet(const char *pMessage) { pev->message = ALLOC_STRING(pMessage); } + const char *MessageGet() const { return STRING(pev->message); } + +private: + hudtextparms_t m_textParms; +}; + +// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator +// Only allows mastered entity to fire if the team matches my team +// +// team index (pulled from server team list "mp_teamlist" +// Flag: Remove on Fire +// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) +class CGameTeamMaster: public CRulePointEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int ObjectCaps() = 0; + virtual BOOL IsTriggered(CBaseEntity *pActivator) = 0; + virtual const char *TeamID() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) == SF_TEAMMASTER_FIREONCE; } + BOOL AnyTeam() const { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) == SF_TEAMMASTER_ANYTEAM; } + +public: + int m_teamIndex; + USE_TYPE triggerType; +}; + +// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team +// Flag: Fire once +// Flag: Clear team -- Sets the team to "NONE" instead of activator +class CGameTeamSet: public CRulePointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_TEAMSET_FIREONCE) == SF_TEAMSET_FIREONCE; } + BOOL ShouldClearTeam() const { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) == SF_TEAMSET_CLEARTEAM; } +}; + +// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired +// Needs master? +class CGamePlayerZone: public CRuleBrushEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +private: + string_t m_iszInTarget; + string_t m_iszOutTarget; + string_t m_iszInCount; + string_t m_iszOutCount; +}; + +// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it +// Flag: Fire once +class CGamePlayerHurt: public CRulePointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_PKILL_FIREONCE) == SF_PKILL_FIREONCE; } +}; + +// CGameCounter / game_counter -- Counts events and fires target +// Flag: Fire once +// Flag: Reset on Fire +class CGameCounter: public CRulePointEntity { +public: + virtual void Spawn() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) == SF_GAMECOUNT_FIREONCE; } + BOOL ResetOnFire() const { return (pev->spawnflags & SF_GAMECOUNT_RESET) == SF_GAMECOUNT_RESET; } + + void CountUp() { pev->frags++; } + void CountDown() { pev->frags--; } + void ResetCount() { pev->frags = pev->dmg; } + + int CountValue() const { return int(pev->frags); } + int LimitValue() const { return int(pev->health); } + BOOL HitLimit() const { return CountValue() == LimitValue(); } + +private: + void SetCountValue(int value) { pev->frags = value; } + void SetInitialValue(int value) { pev->dmg = value; } +}; + +// CGameCounterSet / game_counter_set -- Sets the counter's value +// Flag: Fire once +class CGameCounterSet: public CRulePointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) == SF_GAMECOUNTSET_FIREONCE; } +}; + +// CGamePlayerEquip / game_playerequip -- Sets the default player equipment +// Flag: USE Only +class CGamePlayerEquip: public CRulePointEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + BOOL UseOnly() const { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) == SF_PLAYEREQUIP_USEONLY; } +public: + string_t m_weaponNames[ MAX_EQUIP ]; + int m_weaponCount[ MAX_EQUIP ]; +}; + +// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it +// Flag: Fire once +// Flag: Kill Player +// Flag: Gib Player +class CGamePlayerTeam: public CRulePointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +private: + BOOL RemoveOnFire() const { return (pev->spawnflags & SF_PTEAM_FIREONCE) == SF_PTEAM_FIREONCE; } + BOOL ShouldKillPlayer() const { return (pev->spawnflags & SF_PTEAM_KILL) == SF_PTEAM_KILL; } + BOOL ShouldGibPlayer() const { return (pev->spawnflags & SF_PTEAM_GIB) == SF_PTEAM_GIB; } +}; diff --git a/metamod/include/dlls/monsterevent.h b/metamod/include/dlls/monsterevent.h new file mode 100644 index 0000000..d3f3205 --- /dev/null +++ b/metamod/include/dlls/monsterevent.h @@ -0,0 +1,44 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +typedef struct MonsterEvent_s +{ + int event; + char *options; + +} MonsterEvent_t; + +#define EVENT_SPECIFIC 0 +#define EVENT_SCRIPTED 1000 +#define EVENT_SHARED 2000 +#define EVENT_CLIENT 5000 + +#define MONSTER_EVENT_BODYDROP_LIGHT 2001 +#define MONSTER_EVENT_BODYDROP_HEAVY 2002 +#define MONSTER_EVENT_SWISHSOUND 2010 diff --git a/metamod/include/dlls/monsters.h b/metamod/include/dlls/monsters.h new file mode 100644 index 0000000..842e058 --- /dev/null +++ b/metamod/include/dlls/monsters.h @@ -0,0 +1,113 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define LOCALMOVE_INVALID 0 // move is not possible +#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate +#define LOCALMOVE_VALID 2 // move is possible + +#define SF_MONSTER_WAIT_TILL_SEEN 1 // spawnflag that makes monsters wait until player can see them before attacking. +#define SF_MONSTER_GAG 2 // no idle noises from this monster +#define SF_MONSTER_HITMONSTERCLIP 4 +#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him. + +#define SF_MONSTER_WAIT_FOR_SCRIPT 128 //spawnflag that makes monsters wait to check for attacking until the script is done or they've been attacked +#define SF_MONSTER_PREDISASTER 256 //this is a predisaster scientist or barney. Influences how they speak. +#define SF_MONSTER_FADECORPSE 512 // Fade out corpse after death +#define SF_MONSTER_FALL_TO_GROUND 0x80000000 + +#define SF_MONSTER_TURRET_AUTOACTIVATE 32 +#define SF_MONSTER_TURRET_STARTINACTIVE 64 +#define SF_MONSTER_WAIT_UNTIL_PROVOKED 64 // don't attack the player unless provoked + +#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal +#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck. + +#define MOVE_NORMAL 0 // normal move in the direction monster is facing +#define MOVE_STRAFE 1 // moves in direction specified, no matter which way monster is facing + +#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. +#define R_FR -1 // (FEAR)will run +#define R_NO 0 // (NO RELATIONSHIP) disregard +#define R_DL 1 // (DISLIKE) will attack +#define R_HT 2 // (HATE)will attack this character instead of any visible DISLIKEd characters +#define R_NM 3 // (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what + +#define MEMORY_CLEAR 0 +#define bits_MEMORY_PROVOKED (1 << 0) // right now only used for houndeyes. +#define bits_MEMORY_INCOVER (1 << 1) // monster knows it is in a covered position. +#define bits_MEMORY_SUSPICIOUS (1 << 2) // Ally is suspicious of the player, and will move to provoked more easily +#define bits_MEMORY_PATH_FINISHED (1 << 3) // Finished monster path (just used by big momma for now) +#define bits_MEMORY_ON_PATH (1 << 4) // Moving on a path +#define bits_MEMORY_MOVE_FAILED (1 << 5) // Movement has already failed +#define bits_MEMORY_FLINCHED (1 << 6) // Has already flinched +#define bits_MEMORY_KILLED (1 << 7) // HACKHACK -- remember that I've already called my Killed() +#define bits_MEMORY_CUSTOM4 (1 << 28) // Monster-specific memory +#define bits_MEMORY_CUSTOM3 (1 << 29) // Monster-specific memory +#define bits_MEMORY_CUSTOM2 (1 << 30) // Monster-specific memory +#define bits_MEMORY_CUSTOM1 (1 << 31) // Monster-specific memory + +enum +{ + AITRIGGER_NONE = 0, + AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER, + AITRIGGER_TAKEDAMAGE, + AITRIGGER_HALFHEALTH, + AITRIGGER_DEATH, + AITRIGGER_SQUADMEMBERDIE, + AITRIGGER_SQUADLEADERDIE, + AITRIGGER_HEARWORLD, + AITRIGGER_HEARPLAYER, + AITRIGGER_HEARCOMBAT, + AITRIGGER_SEEPLAYER_UNCONDITIONAL, + AITRIGGER_SEEPLAYER_NOT_IN_COMBAT, +}; + +enum HitBoxGroup +{ + HITGROUP_GENERIC = 0, + HITGROUP_HEAD, + HITGROUP_CHEST, + HITGROUP_STOMACH, + HITGROUP_LEFTARM, + HITGROUP_RIGHTARM, + HITGROUP_LEFTLEG, + HITGROUP_RIGHTLEG, + HITGROUP_SHIELD, + NUM_HITGROUPS, +}; + +class CGib: public CBaseEntity { +public: + virtual int ObjectCaps() = 0; +public: + int m_bloodColor; + int m_cBloodDecals; + int m_material; + float m_lifeTime; +}; diff --git a/metamod/include/dlls/mortar.h b/metamod/include/dlls/mortar.h new file mode 100644 index 0000000..e74636c --- /dev/null +++ b/metamod/include/dlls/mortar.h @@ -0,0 +1,55 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CFuncMortarField: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + + // Bmodels don't go across transitions + virtual int ObjectCaps() = 0; +public: + int m_iszXController; + int m_iszYController; + float m_flSpread; + float m_flDelay; + int m_iCount; + int m_fControl; +}; + +class CMortar: public CGrenade { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; +public: + int m_spriteTexture; +}; diff --git a/metamod/include/dlls/observer.h b/metamod/include/dlls/observer.h new file mode 100644 index 0000000..67585a5 --- /dev/null +++ b/metamod/include/dlls/observer.h @@ -0,0 +1,32 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define CAMERA_MODE_SPEC_ANYONE 0 +#define CAMERA_MODE_SPEC_ONLY_TEAM 1 +#define CAMERA_MODE_SPEC_ONLY_FRIST_PERSON 2 diff --git a/metamod/include/dlls/pathcorner.h b/metamod/include/dlls/pathcorner.h new file mode 100644 index 0000000..5be28a3 --- /dev/null +++ b/metamod/include/dlls/pathcorner.h @@ -0,0 +1,39 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CPathCorner: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual float GetDelay() = 0; +private: + float m_flWait; +}; diff --git a/metamod/include/dlls/plats.h b/metamod/include/dlls/plats.h new file mode 100644 index 0000000..ec67be3 --- /dev/null +++ b/metamod/include/dlls/plats.h @@ -0,0 +1,178 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SF_PLAT_TOGGLE 0x0001 + +#define TRAIN_STARTPITCH 60 +#define TRAIN_MAXPITCH 200 +#define TRAIN_MAXSPEED 1000 + +#define SF_TRACK_ACTIVATETRAIN 0x00000001 +#define SF_TRACK_RELINK 0x00000002 +#define SF_TRACK_ROTMOVE 0x00000004 +#define SF_TRACK_STARTBOTTOM 0x00000008 +#define SF_TRACK_DONT_MOVE 0x00000010 + +#define FGUNTARGET_START_ON 0x0001 + +class CBasePlatTrain: public CBaseToggle { +public: + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + + // This is done to fix spawn flag collisions between this class and a derived class + virtual BOOL IsTogglePlat() = 0; +public: + byte m_bMoveSnd; + byte m_bStopSnd; + float m_volume; +}; + +class CFuncPlat: public CBasePlatTrain { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; + virtual void GoUp() = 0; + virtual void GoDown() = 0; + virtual void HitTop() = 0; + virtual void HitBottom() = 0; +}; + +class CPlatTrigger: public CBaseEntity { +public: + virtual int ObjectCaps() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +public: + CFuncPlat *m_pPlatform; +}; + +class CFuncPlatRot: public CFuncPlat { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void GoUp() = 0; + virtual void GoDown() = 0; + virtual void HitTop() = 0; + virtual void HitBottom() = 0; +public: + Vector m_end; + Vector m_start; +}; + +class CFuncTrain: public CBasePlatTrain { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Activate() = 0; + virtual void OverrideReset() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + Vector m_vStartPosition; + entvars_t *m_pevFirstTarget; + entvars_t *m_pevCurrentTarget; + int m_sounds; + BOOL m_activated; +}; + +class CFuncTrainControls: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int ObjectCaps() = 0; +}; + +class CFuncTrackChange: public CFuncPlatRot { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void OverrideReset() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual BOOL IsTogglePlat() = 0; + virtual void GoUp() = 0; + virtual void GoDown() = 0; + virtual void HitTop() = 0; + virtual void HitBottom() = 0; + virtual void UpdateAutoTargets(int toggleState) = 0; + +public: + void DisableUse() { m_use = 0; } + void EnableUse() { m_use = 1; } + + int UseEnabled() const { return m_use; } + +public: + static TYPEDESCRIPTION IMPL(m_SaveData)[9]; + + CPathTrack *m_trackTop; + CPathTrack *m_trackBottom; + CFuncTrackTrain *m_train; + + int m_trackTopName; + int m_trackBottomName; + int m_trainName; + + TRAIN_CODE m_code; + int m_targetState; + int m_use; +}; + +class CFuncTrackAuto: public CFuncTrackChange { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void UpdateAutoTargets(int toggleState) = 0; +}; + +class CGunTarget: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Activate() = 0; + virtual int Classify() = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual int BloodColor() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual Vector BodyTarget(const Vector &posSrc) = 0; +private: + BOOL m_on; +}; diff --git a/metamod/include/dlls/player.h b/metamod/include/dlls/player.h new file mode 100644 index 0000000..690cd93 --- /dev/null +++ b/metamod/include/dlls/player.h @@ -0,0 +1,578 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "pm_materials.h" +#include "hintmessage.h" +#include "unisignals.h" + +#define MIN_BUY_TIME 15 // the minimum threshold values for cvar mp_buytime 15 sec's + +#define MAX_BUFFER_MENU 175 +#define MAX_BUFFER_MENU_BRIEFING 50 + +#define MAX_PLAYER_NAME_LENGTH 32 +#define MAX_AUTOBUY_LENGTH 256 +#define MAX_REBUY_LENGTH 256 + +#define MAX_RECENT_PATH 20 +#define MAX_HOSTAGE_ICON 4 // the maximum number of icons of the hostages in the HUD + +#define SUITUPDATETIME 3.5 +#define SUITFIRSTUPDATETIME 0.1 + +#define PLAYER_FATAL_FALL_SPEED 1100.0f +#define PLAYER_MAX_SAFE_FALL_SPEED 500.0f +#define PLAYER_USE_RADIUS 64.0f + +#define ARMOR_RATIO 0.5 // Armor Takes 50% of the damage +#define ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health + +#define FLASH_DRAIN_TIME 1.2 // 100 units/3 minutes +#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) + +// damage per unit per second. +#define DAMAGE_FOR_FALL_SPEED 100.0f / (PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED) +#define PLAYER_MIN_BOUNCE_SPEED 350.0f + +// won't punch player's screen/make scrape noise unless player falling at least this fast. +#define PLAYER_FALL_PUNCH_THRESHHOLD 250.0f + +// Money blinks few of times on the freeze period +// NOTE: It works for CZ +#define MONEY_BLINK_AMOUNT 30 + +// Player physics flags bits +// CBasePlayer::m_afPhysicsFlags +#define PFLAG_ONLADDER (1<<0) +#define PFLAG_ONSWING (1<<0) +#define PFLAG_ONTRAIN (1<<1) +#define PFLAG_ONBARNACLE (1<<2) +#define PFLAG_DUCKING (1<<3) // In the process of ducking, but totally squatted yet +#define PFLAG_USING (1<<4) // Using a continuous entity +#define PFLAG_OBSERVER (1<<5) // player is locked in stationary cam mode. Spectators can move, observers can't. + +#define TRAIN_OFF 0x00 +#define TRAIN_NEUTRAL 0x01 +#define TRAIN_SLOW 0x02 +#define TRAIN_MEDIUM 0x03 +#define TRAIN_FAST 0x04 +#define TRAIN_BACK 0x05 + +#define TRAIN_ACTIVE 0x80 +#define TRAIN_NEW 0xc0 + +#define SIGNAL_BUY (1<<0) +#define SIGNAL_BOMB (1<<1) +#define SIGNAL_RESCUE (1<<2) +#define SIGNAL_ESCAPE (1<<3) +#define SIGNAL_VIPSAFETY (1<<4) + +#define IGNOREMSG_NONE 0 +#define IGNOREMSG_ENEMY 1 +#define IGNOREMSG_TEAM 2 + +// max of 4 suit sentences queued up at any time +#define CSUITPLAYLIST 4 + +#define SUIT_GROUP TRUE +#define SUIT_SENTENCE FALSE + +#define SUIT_REPEAT_OK 0 +#define SUIT_NEXT_IN_30SEC 30 +#define SUIT_NEXT_IN_1MIN 60 +#define SUIT_NEXT_IN_5MIN 300 +#define SUIT_NEXT_IN_10MIN 600 +#define SUIT_NEXT_IN_30MIN 1800 +#define SUIT_NEXT_IN_1HOUR 3600 + +#define TEAM_NAME_LENGTH 16 + +#define MAX_ID_RANGE 2048.0f +#define MAX_SPECTATOR_ID_RANGE 8192.0f +#define SBAR_STRING_SIZE 128 + +#define SBAR_TARGETTYPE_TEAMMATE 1 +#define SBAR_TARGETTYPE_ENEMY 2 +#define SBAR_TARGETTYPE_HOSTAGE 3 + +#define CHAT_INTERVAL 1.0f +#define CSUITNOREPEAT 32 + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 + +#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" +#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" + +// custom enum +enum RewardType +{ + RT_NONE, + RT_ROUND_BONUS, + RT_PLAYER_RESET, + RT_PLAYER_BOUGHT_SOMETHING, + RT_HOSTAGE_TOOK, + RT_HOSTAGE_RESCUED, + RT_HOSTAGE_DAMAGED, + RT_HOSTAGE_KILLED, + RT_TEAMMATES_KILLED, + RT_ENEMY_KILLED, + RT_INTO_GAME, + RT_VIP_KILLED, + RT_VIP_RESCUED_MYSELF +}; + +enum PLAYER_ANIM +{ + PLAYER_IDLE, + PLAYER_WALK, + PLAYER_JUMP, + PLAYER_SUPERJUMP, + PLAYER_DIE, + PLAYER_ATTACK1, + PLAYER_ATTACK2, + PLAYER_FLINCH, + PLAYER_LARGE_FLINCH, + PLAYER_RELOAD, + PLAYER_HOLDBOMB +}; + +enum _Menu +{ + Menu_OFF, + Menu_ChooseTeam, + Menu_IGChooseTeam, + Menu_ChooseAppearance, + Menu_Buy, + Menu_BuyPistol, + Menu_BuyRifle, + Menu_BuyMachineGun, + Menu_BuyShotgun, + Menu_BuySubMachineGun, + Menu_BuyItem, + Menu_Radio1, + Menu_Radio2, + Menu_Radio3, + Menu_ClientBuy +}; + +enum TeamName +{ + UNASSIGNED, + TERRORIST, + CT, + SPECTATOR, +}; + +enum ModelName +{ + MODEL_UNASSIGNED, + MODEL_URBAN, + MODEL_TERROR, + MODEL_LEET, + MODEL_ARCTIC, + MODEL_GSG9, + MODEL_GIGN, + MODEL_SAS, + MODEL_GUERILLA, + MODEL_VIP, + MODEL_MILITIA, + MODEL_SPETSNAZ, + MODEL_AUTO +}; + +enum JoinState +{ + JOINED, + SHOWLTEXT, + READINGLTEXT, + SHOWTEAMSELECT, + PICKINGTEAM, + GETINTOGAME +}; + +enum TrackCommands +{ + CMD_SAY = 0, + CMD_SAYTEAM, + CMD_FULLUPDATE, + CMD_VOTE, + CMD_VOTEMAP, + CMD_LISTMAPS, + CMD_LISTPLAYERS, + CMD_NIGHTVISION, + COMMANDS_TO_TRACK, +}; + +struct RebuyStruct +{ + int m_primaryWeapon; + int m_primaryAmmo; + int m_secondaryWeapon; + int m_secondaryAmmo; + int m_heGrenade; + int m_flashbang; + int m_smokeGrenade; + int m_defuser; + int m_nightVision; + ArmorType m_armor; +}; + +enum ThrowDirection +{ + THROW_NONE, + THROW_FORWARD, + THROW_BACKWARD, + THROW_HITVEL, + THROW_BOMB, + THROW_GRENADE, + THROW_HITVEL_MINUS_AIRVEL +}; + +enum sbar_data +{ + SBAR_ID_TARGETTYPE = 1, + SBAR_ID_TARGETNAME, + SBAR_ID_TARGETHEALTH, + SBAR_END +}; + +enum MusicState { SILENT, CALM, INTENSE }; + +class CCSPlayer; + +class CStripWeapons: public CPointEntity { +public: + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +// Multiplayer intermission spots. +class CInfoIntermission: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void Think() = 0; +}; + +// Dead HEV suit prop +class CDeadHEV: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Classify() = 0; +public: + int m_iPose; // which sequence to display -- temporary, don't need to save + static char *m_szPoses[4]; +}; + +class CSprayCan: public CBaseEntity { +public: + virtual void Think() = 0; + virtual int ObjectCaps() = 0; +}; + +class CBloodSplat: public CBaseEntity { +public: +}; + +class CBasePlayer: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual int Classify() = 0; + virtual void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) = 0; + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + virtual BOOL TakeHealth(float flHealth, int bitsDamageType) = 0; + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual void AddPoints(int score, BOOL bAllowNegativeScore) = 0; + virtual void AddPointsToTeam(int score, BOOL bAllowNegativeScore) = 0; + virtual BOOL AddPlayerItem(CBasePlayerItem *pItem) = 0; + virtual BOOL RemovePlayerItem(CBasePlayerItem *pItem) = 0; + virtual int GiveAmmo(int iAmount, char *szName, int iMax) = 0; + virtual void StartSneaking() = 0; + virtual void StopSneaking() = 0; + virtual BOOL IsSneaking() = 0; + virtual BOOL IsAlive() = 0; + virtual BOOL IsPlayer() = 0; + virtual BOOL IsNetClient() = 0; + virtual const char *TeamID() = 0; + virtual BOOL FBecomeProne() = 0; + virtual Vector BodyTarget(const Vector &posSrc) = 0; + virtual int Illumination() = 0; + virtual BOOL ShouldFadeOnDeath() = 0; + virtual void ResetMaxSpeed() = 0; + virtual void Jump() = 0; + virtual void Duck() = 0; + virtual void PreThink() = 0; + virtual void PostThink() = 0; + virtual Vector GetGunPosition() = 0; + virtual BOOL IsBot() = 0; + virtual void UpdateClientData() = 0; + virtual void ImpulseCommands() = 0; + virtual void RoundRespawn() = 0; + virtual Vector GetAutoaimVector(float flDelta) = 0; + virtual void Blind(float flUntilTime, float flHoldTime, float flFadeTime, int iAlpha) = 0; + virtual void OnTouchingWeapon(CWeaponBox *pWeapon) = 0; +public: + static CBasePlayer *Instance(edict_t *pent) { return (CBasePlayer *)GET_PRIVATE(pent ? pent : ENT(0)); } + static CBasePlayer *Instance(entvars_t *pev) { return Instance(ENT(pev)); } + static CBasePlayer *Instance(int offset) { return Instance(ENT(offset)); } + + int IsObserver() { return pev->iuser1; } + void SetWeaponAnimType(const char *szExtention) { strcpy(m_szAnimExtention, szExtention); } + bool IsProtectedByShield() { return m_bOwnsShield && m_bShieldDrawn; } + bool IsReloading() const; + bool IsBlind() const { return (m_blindUntilTime > gpGlobals->time); } + bool IsAutoFollowAllowed() const { return (gpGlobals->time > m_allowAutoFollowTime); } + void InhibitAutoFollow(float duration) { m_allowAutoFollowTime = gpGlobals->time + duration; } + void AllowAutoFollow() { m_allowAutoFollowTime = 0; } + void SetObserverAutoDirector(bool val) { m_bObserverAutoDirector = val; } + bool CanSwitchObserverModes() const { return m_canSwitchObserverModes; } + CCSPlayer *CSPlayer() const; +public: + enum { MaxLocationLen = 32 }; + + int random_seed; + unsigned short m_usPlayerBleed; + EHANDLE m_hObserverTarget; + float m_flNextObserverInput; + int m_iObserverWeapon; + int m_iObserverC4State; + bool m_bObserverHasDefuser; + int m_iObserverLastMode; + float m_flFlinchTime; + float m_flAnimTime; + bool m_bHighDamage; + float m_flVelocityModifier; + int m_iLastZoom; + bool m_bResumeZoom; + float m_flEjectBrass; + ArmorType m_iKevlar; + bool m_bNotKilled; + TeamName m_iTeam; + int m_iAccount; + bool m_bHasPrimary; + float m_flDeathThrowTime; + int m_iThrowDirection; + float m_flLastTalk; + bool m_bJustConnected; + bool m_bContextHelp; + JoinState m_iJoiningState; + CBaseEntity *m_pIntroCamera; + float m_fIntroCamTime; + float m_fLastMovement; + bool m_bMissionBriefing; + bool m_bTeamChanged; + ModelName m_iModelName; + int m_iTeamKills; + int m_iIgnoreGlobalChat; + bool m_bHasNightVision; + bool m_bNightVisionOn; + Vector m_vRecentPath[MAX_RECENT_PATH]; + float m_flIdleCheckTime; + float m_flRadioTime; + int m_iRadioMessages; + bool m_bIgnoreRadio; + bool m_bHasC4; + bool m_bHasDefuser; + bool m_bKilledByBomb; + Vector m_vBlastVector; + bool m_bKilledByGrenade; + CHintMessageQueue m_hintMessageQueue; + int m_flDisplayHistory; + _Menu m_iMenu; + int m_iChaseTarget; + CBaseEntity *m_pChaseTarget; + float m_fCamSwitch; + bool m_bEscaped; + bool m_bIsVIP; + float m_tmNextRadarUpdate; + Vector m_vLastOrigin; + int m_iCurrentKickVote; + float m_flNextVoteTime; + bool m_bJustKilledTeammate; + int m_iHostagesKilled; + int m_iMapVote; + bool m_bCanShoot; + float m_flLastFired; + float m_flLastAttackedTeammate; + bool m_bHeadshotKilled; + bool m_bPunishedForTK; + bool m_bReceivesNoMoneyNextRound; + int m_iTimeCheckAllowed; + bool m_bHasChangedName; + char m_szNewName[MAX_PLAYER_NAME_LENGTH]; + bool m_bIsDefusing; + float m_tmHandleSignals; + CUnifiedSignals m_signals; + edict_t *m_pentCurBombTarget; + int m_iPlayerSound; + int m_iTargetVolume; + int m_iWeaponVolume; + int m_iExtraSoundTypes; + int m_iWeaponFlash; + float m_flStopExtraSoundTime; + float m_flFlashLightTime; + int m_iFlashBattery; + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + edict_t *m_pentSndLast; + float m_flSndRoomtype; + float m_flSndRange; + float m_flFallVelocity; + int m_rgItems[MAX_ITEMS]; + int m_fNewAmmo; + unsigned int m_afPhysicsFlags; + float m_fNextSuicideTime; + float m_flTimeStepSound; + float m_flTimeWeaponIdle; + float m_flSwimTime; + float m_flDuckTime; + float m_flWallJumpTime; + float m_flSuitUpdate; + int m_rgSuitPlayList[CSUITPLAYLIST]; + int m_iSuitPlayNext; + int m_rgiSuitNoRepeat[CSUITNOREPEAT]; + float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; + int m_lastDamageAmount; + float m_tbdPrev; + float m_flgeigerRange; + float m_flgeigerDelay; + int m_igeigerRangePrev; + int m_iStepLeft; + char m_szTextureName[CBTEXTURENAMEMAX]; + char m_chTextureType; + int m_idrowndmg; + int m_idrownrestored; + int m_bitsHUDDamage; + BOOL m_fInitHUD; + BOOL m_fGameHUDInitialized; + int m_iTrain; + BOOL m_fWeapon; + EHANDLE m_pTank; + float m_fDeadTime; + BOOL m_fNoPlayerSound; + BOOL m_fLongJump; + float m_tSneaking; + int m_iUpdateTime; + int m_iClientHealth; + int m_iClientBattery; + int m_iHideHUD; + int m_iClientHideHUD; + int m_iFOV; + int m_iClientFOV; + int m_iNumSpawns; + CBaseEntity *m_pObserver; + CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; + CBasePlayerItem *m_pActiveItem; + CBasePlayerItem *m_pClientActiveItem; + CBasePlayerItem *m_pLastItem; + int m_rgAmmo[MAX_AMMO_SLOTS]; + int m_rgAmmoLast[MAX_AMMO_SLOTS]; + Vector m_vecAutoAim; + BOOL m_fOnTarget; + int m_iDeaths; + int m_izSBarState[SBAR_END]; + float m_flNextSBarUpdateTime; + float m_flStatusBarDisappearDelay; + char m_SbarString0[SBAR_STRING_SIZE]; + int m_lastx; + int m_lasty; + int m_nCustomSprayFrames; + float m_flNextDecalTime; + char m_szTeamName[TEAM_NAME_LENGTH]; + int m_modelIndexPlayer; + char m_szAnimExtention[32]; + int m_iGaitsequence; + float m_flGaitframe; + float m_flGaityaw; + Vector m_prevgaitorigin; + float m_flPitch; + float m_flYaw; + float m_flGaitMovement; + int m_iAutoWepSwitch; + bool m_bVGUIMenus; + bool m_bShowHints; + bool m_bShieldDrawn; + bool m_bOwnsShield; + bool m_bWasFollowing; + float m_flNextFollowTime; + float m_flYawModifier; + float m_blindUntilTime; + float m_blindStartTime; + float m_blindHoldTime; + float m_blindFadeTime; + int m_blindAlpha; + float m_allowAutoFollowTime; + char m_autoBuyString[MAX_AUTOBUY_LENGTH]; + char *m_rebuyString; + RebuyStruct m_rebuyStruct; + bool m_bIsInRebuy; + float m_flLastUpdateTime; + char m_lastLocation[MaxLocationLen]; + float m_progressStart; + float m_progressEnd; + bool m_bObserverAutoDirector; + bool m_canSwitchObserverModes; + float m_heartBeatTime; + float m_intenseTimestamp; + float m_silentTimestamp; + MusicState m_musicState; + float m_flLastCommandTime[COMMANDS_TO_TRACK]; +}; + +class CWShield: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +public: + void SetCantBePickedUpByUser(CBaseEntity *pEntity, float time) { m_hEntToIgnoreTouchesFrom = pEntity; m_flTimeToIgnoreTouches = gpGlobals->time + time; } +public: + EHANDLE m_hEntToIgnoreTouchesFrom; + float m_flTimeToIgnoreTouches; +}; + +inline bool CBasePlayer::IsReloading() const +{ + CBasePlayerWeapon *weapon = static_cast(m_pActiveItem); + + if (weapon != NULL && weapon->m_fInReload) + return true; + + return false; +} + +inline CCSPlayer *CBasePlayer::CSPlayer() const { + return reinterpret_cast(this->m_pEntity); +} diff --git a/metamod/include/dlls/regamedll_api.h b/metamod/include/dlls/regamedll_api.h new file mode 100644 index 0000000..afc362d --- /dev/null +++ b/metamod/include/dlls/regamedll_api.h @@ -0,0 +1,413 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "archtypes.h" +#include "regamedll_interfaces.h" +#include "hookchains.h" +#include "interface.h" +#include "player.h" +#include "gamerules.h" +#include "client.h" +#include "items.h" + +#define REGAMEDLL_API_VERSION_MAJOR 4 +#define REGAMEDLL_API_VERSION_MINOR 1 + +// CBasePlayer::Spawn hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Spawn; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Spawn; + +// CBasePlayer::Precache hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Precache; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Precache; + +// CBasePlayer::ObjectCaps hook +typedef IHookChainClass IReGameHook_CBasePlayer_ObjectCaps; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_ObjectCaps; + +// CBasePlayer::Classify hook +typedef IHookChainClass IReGameHook_CBasePlayer_Classify; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Classify; + +// CBasePlayer::TraceAttack hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_TraceAttack; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TraceAttack; + +// CBasePlayer::TakeDamage hook +typedef IHookChainClass IReGameHook_CBasePlayer_TakeDamage; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TakeDamage; + +// CBasePlayer::TakeHealth hook +typedef IHookChainClass IReGameHook_CBasePlayer_TakeHealth; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TakeHealth; + +// CBasePlayer::Killed hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Killed; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Killed; + +// CBasePlayer::AddPoints hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_AddPoints; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_AddPoints; + +// CBasePlayer::AddPointsToTeam hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_AddPointsToTeam; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_AddPointsToTeam; + +// CBasePlayer::AddPlayerItem hook +typedef IHookChainClass IReGameHook_CBasePlayer_AddPlayerItem; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_AddPlayerItem; + +// CBasePlayer::RemovePlayerItem hook +typedef IHookChainClass IReGameHook_CBasePlayer_RemovePlayerItem; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RemovePlayerItem; + +// CBasePlayer::GiveAmmo hook +typedef IHookChainClass IReGameHook_CBasePlayer_GiveAmmo; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_GiveAmmo; + +// CBasePlayer::ResetMaxSpeed hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_ResetMaxSpeed; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_ResetMaxSpeed; + +// CBasePlayer::Jump hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Jump; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Jump; + +// CBasePlayer::Duck hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Duck; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Duck; + +// CBasePlayer::PreThink hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_PreThink; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_PreThink; + +// CBasePlayer::PostThink hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_PostThink; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_PostThink; + +// CBasePlayer::UpdateClientData hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_UpdateClientData; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_UpdateClientData; + +// CBasePlayer::ImpulseCommands hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_ImpulseCommands; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_ImpulseCommands; + +// CBasePlayer::RoundRespawn hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_RoundRespawn; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RoundRespawn; + +// CBasePlayer::Blind hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_Blind; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Blind; + +// CBasePlayer::Observer_IsValidTarget hook +typedef IHookChainClass IReGameHook_CBasePlayer_Observer_IsValidTarget; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_Observer_IsValidTarget; + +// CBasePlayer::SetAnimation hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_SetAnimation; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_SetAnimation; + +// CBasePlayer::GiveDefaultItems hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_GiveDefaultItems; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_GiveDefaultItems; + +// CBasePlayer::GiveNamedItem hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_GiveNamedItem; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_GiveNamedItem; + +// CBasePlayer::AddAccount hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_AddAccount; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_AddAccount; + +// CBasePlayer::GiveShield hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_GiveShield; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_GiveShield; + +// CBasePlayer:SetClientUserInfoModel hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_SetClientUserInfoModel; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_SetClientUserInfoModel; + +// CBasePlayer:SetClientUserInfoName hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_SetClientUserInfoName; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_SetClientUserInfoName; + +// CBasePlayer::HasRestrictItem hook +typedef IHookChainClass IReGameHook_CBasePlayer_HasRestrictItem; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_HasRestrictItem; + +// CBasePlayer::DropPlayerItem hook +typedef IVoidHookChainClass IReGameHook_CBasePlayer_DropPlayerItem; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBasePlayer_DropPlayerItem; + +// CBaseAnimating::ResetSequenceInfo hook +typedef IVoidHookChainClass IReGameHook_CBaseAnimating_ResetSequenceInfo; +typedef IVoidHookChainRegistryClass IReGameHookRegistry_CBaseAnimating_ResetSequenceInfo; + +// GetForceCamera hook +typedef IHookChain IReGameHook_GetForceCamera; +typedef IHookChainRegistry IReGameHookRegistry_GetForceCamera; + +// PlayerBlind hook +typedef IVoidHookChain IReGameHook_PlayerBlind; +typedef IVoidHookChainRegistry IReGameHookRegistry_PlayerBlind; + +// RadiusFlash_TraceLine hook +typedef IVoidHookChain IReGameHook_RadiusFlash_TraceLine; +typedef IVoidHookChainRegistry IReGameHookRegistry_RadiusFlash_TraceLine; + +// RoundEnd hook +typedef IHookChain IReGameHook_RoundEnd; +typedef IHookChainRegistry IReGameHookRegistry_RoundEnd; + +// InstallGameRules hook +typedef IHookChain IReGameHook_InstallGameRules; +typedef IHookChainRegistry IReGameHookRegistry_InstallGameRules; + +// PM_Init hook +typedef IVoidHookChain IReGameHook_PM_Init; +typedef IVoidHookChainRegistry IReGameHookRegistry_PM_Init; + +// PM_Move hook +typedef IVoidHookChain IReGameHook_PM_Move; +typedef IVoidHookChainRegistry IReGameHookRegistry_PM_Move; + +// PM_AirMove hook +typedef IVoidHookChain IReGameHook_PM_AirMove; +typedef IVoidHookChainRegistry IReGameHookRegistry_PM_AirMove; + +// HandleMenu_ChooseAppearance hook +typedef IVoidHookChain IReGameHook_HandleMenu_ChooseAppearance; +typedef IVoidHookChainRegistry IReGameHookRegistry_HandleMenu_ChooseAppearance; + +// HandleMenu_ChooseTeam hook +typedef IHookChain IReGameHook_HandleMenu_ChooseTeam; +typedef IHookChainRegistry IReGameHookRegistry_HandleMenu_ChooseTeam; + +// ShowMenu hook +typedef IVoidHookChain IReGameHook_ShowMenu; +typedef IVoidHookChainRegistry IReGameHookRegistry_ShowMenu; + +// ShowVGUIMenu hook +typedef IVoidHookChain IReGameHook_ShowVGUIMenu; +typedef IVoidHookChainRegistry IReGameHookRegistry_ShowVGUIMenu; + +// CHalfLifeMultiplay::FShouldSwitchWeapon hook +typedef IHookChain IReGameHook_CSGameRules_FShouldSwitchWeapon; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_FShouldSwitchWeapon; + +// CHalfLifeMultiplay::GetNextBestWeapon hook +typedef IHookChain IReGameHook_CSGameRules_GetNextBestWeapon; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GetNextBestWeapon; + +// CHalfLifeMultiplay::FlPlayerFallDamage hook +typedef IHookChain IReGameHook_CSGameRules_FlPlayerFallDamage; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_FlPlayerFallDamage; + +// CHalfLifeMultiplay::FPlayerCanTakeDamage hook +typedef IHookChain IReGameHook_CSGameRules_FPlayerCanTakeDamage; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_FPlayerCanTakeDamage; + +// CHalfLifeMultiplay::PlayerSpawn hook +typedef IVoidHookChain IReGameHook_CSGameRules_PlayerSpawn; +typedef IVoidHookChainRegistry IReGameHookRegistry_CSGameRules_PlayerSpawn; + +// CHalfLifeMultiplay::FPlayerCanRespawn hook +typedef IHookChain IReGameHook_CSGameRules_FPlayerCanRespawn; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_FPlayerCanRespawn; + +// CHalfLifeMultiplay::GetPlayerSpawnSpot hook +typedef IHookChain IReGameHook_CSGameRules_GetPlayerSpawnSpot; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_GetPlayerSpawnSpot; + +// CHalfLifeMultiplay::ClientUserInfoChanged hook +typedef IVoidHookChain IReGameHook_CSGameRules_ClientUserInfoChanged; +typedef IVoidHookChainRegistry IReGameHookRegistry_CSGameRules_ClientUserInfoChanged; + +// CHalfLifeMultiplay::PlayerKilled hook +typedef IVoidHookChain IReGameHook_CSGameRules_PlayerKilled; +typedef IVoidHookChainRegistry IReGameHookRegistry_CSGameRules_PlayerKilled; + +// CHalfLifeMultiplay::DeathNotice hook +typedef IVoidHookChain IReGameHook_CSGameRules_DeathNotice; +typedef IVoidHookChainRegistry IReGameHookRegistry_CSGameRules_DeathNotice; + +// CHalfLifeMultiplay::CanHavePlayerItem hook +typedef IHookChain IReGameHook_CSGameRules_CanHavePlayerItem; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_CanHavePlayerItem; + +// CHalfLifeMultiplay::DeadPlayerWeapons hook +typedef IHookChain IReGameHook_CSGameRules_DeadPlayerWeapons; +typedef IHookChainRegistry IReGameHookRegistry_CSGameRules_DeadPlayerWeapons; + +// CHalfLifeMultiplay::ServerDeactivate hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_ServerDeactivate; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_ServerDeactivate; + +// CHalfLifeMultiplay::CheckMapConditions hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_CheckMapConditions; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_CheckMapConditions; + +// CHalfLifeMultiplay::CleanUpMap hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_CleanUpMap; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_CleanUpMap; + +// CHalfLifeMultiplay::RestartRound hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_RestartRound; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_RestartRound; + +// CHalfLifeMultiplay::CheckWinConditions hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_CheckWinConditions; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_CheckWinConditions; + +// CHalfLifeMultiplay::RemoveGuns hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_RemoveGuns; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_RemoveGuns; + +// CHalfLifeMultiplay::GiveC4 hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_GiveC4; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_GiveC4; + +// CHalfLifeMultiplay::ChangeLevel hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_ChangeLevel; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_ChangeLevel; + +// CHalfLifeMultiplay::GoToIntermission hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_GoToIntermission; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_GoToIntermission; + +// CHalfLifeMultiplay::BalanceTeams hook +typedef IVoidHookChain<> IReGameHook_CSGameRules_BalanceTeams; +typedef IVoidHookChainRegistry<> IReGameHookRegistry_CSGameRules_BalanceTeams; + +class IReGameHookchains { +public: + virtual ~IReGameHookchains() {} + // CBasePlayer virtual + virtual IReGameHookRegistry_CBasePlayer_Spawn* CBasePlayer_Spawn() = 0; + virtual IReGameHookRegistry_CBasePlayer_Precache* CBasePlayer_Precache() = 0; + virtual IReGameHookRegistry_CBasePlayer_ObjectCaps* CBasePlayer_ObjectCaps() = 0; + virtual IReGameHookRegistry_CBasePlayer_Classify* CBasePlayer_Classify() = 0; + virtual IReGameHookRegistry_CBasePlayer_TraceAttack* CBasePlayer_TraceAttack() = 0; + virtual IReGameHookRegistry_CBasePlayer_TakeDamage* CBasePlayer_TakeDamage() = 0; + virtual IReGameHookRegistry_CBasePlayer_TakeHealth* CBasePlayer_TakeHealth() = 0; + virtual IReGameHookRegistry_CBasePlayer_Killed* CBasePlayer_Killed() = 0; + virtual IReGameHookRegistry_CBasePlayer_AddPoints* CBasePlayer_AddPoints() = 0; + virtual IReGameHookRegistry_CBasePlayer_AddPointsToTeam* CBasePlayer_AddPointsToTeam() = 0; + virtual IReGameHookRegistry_CBasePlayer_AddPlayerItem* CBasePlayer_AddPlayerItem() = 0; + virtual IReGameHookRegistry_CBasePlayer_RemovePlayerItem* CBasePlayer_RemovePlayerItem() = 0; + virtual IReGameHookRegistry_CBasePlayer_GiveAmmo* CBasePlayer_GiveAmmo() = 0; + virtual IReGameHookRegistry_CBasePlayer_ResetMaxSpeed* CBasePlayer_ResetMaxSpeed() = 0; + virtual IReGameHookRegistry_CBasePlayer_Jump* CBasePlayer_Jump() = 0; + virtual IReGameHookRegistry_CBasePlayer_Duck* CBasePlayer_Duck() = 0; + virtual IReGameHookRegistry_CBasePlayer_PreThink* CBasePlayer_PreThink() = 0; + virtual IReGameHookRegistry_CBasePlayer_PostThink* CBasePlayer_PostThink() = 0; + virtual IReGameHookRegistry_CBasePlayer_UpdateClientData* CBasePlayer_UpdateClientData() = 0; + virtual IReGameHookRegistry_CBasePlayer_ImpulseCommands* CBasePlayer_ImpulseCommands() = 0; + virtual IReGameHookRegistry_CBasePlayer_RoundRespawn* CBasePlayer_RoundRespawn() = 0; + virtual IReGameHookRegistry_CBasePlayer_Blind* CBasePlayer_Blind() = 0; + + virtual IReGameHookRegistry_CBasePlayer_Observer_IsValidTarget* CBasePlayer_Observer_IsValidTarget() = 0; + virtual IReGameHookRegistry_CBasePlayer_SetAnimation* CBasePlayer_SetAnimation() = 0; + virtual IReGameHookRegistry_CBasePlayer_GiveDefaultItems* CBasePlayer_GiveDefaultItems() = 0; + virtual IReGameHookRegistry_CBasePlayer_GiveNamedItem* CBasePlayer_GiveNamedItem() = 0; + virtual IReGameHookRegistry_CBasePlayer_AddAccount* CBasePlayer_AddAccount() = 0; + virtual IReGameHookRegistry_CBasePlayer_GiveShield* CBasePlayer_GiveShield() = 0; + virtual IReGameHookRegistry_CBasePlayer_SetClientUserInfoModel* CBasePlayer_SetClientUserInfoModel() = 0; + virtual IReGameHookRegistry_CBasePlayer_SetClientUserInfoName* CBasePlayer_SetClientUserInfoName() = 0; + virtual IReGameHookRegistry_CBasePlayer_HasRestrictItem* CBasePlayer_HasRestrictItem() = 0; + virtual IReGameHookRegistry_CBasePlayer_DropPlayerItem* CBasePlayer_DropPlayerItem() = 0; + virtual IReGameHookRegistry_CBaseAnimating_ResetSequenceInfo* CBaseAnimating_ResetSequenceInfo() = 0; + + virtual IReGameHookRegistry_GetForceCamera* GetForceCamera() = 0; + virtual IReGameHookRegistry_PlayerBlind* PlayerBlind() = 0; + virtual IReGameHookRegistry_RadiusFlash_TraceLine* RadiusFlash_TraceLine() = 0; + virtual IReGameHookRegistry_RoundEnd* RoundEnd() = 0; + virtual IReGameHookRegistry_InstallGameRules* InstallGameRules() = 0; + virtual IReGameHookRegistry_PM_Init* PM_Init() = 0; + virtual IReGameHookRegistry_PM_Move* PM_Move() = 0; + virtual IReGameHookRegistry_PM_AirMove* PM_AirMove() = 0; + virtual IReGameHookRegistry_HandleMenu_ChooseAppearance* HandleMenu_ChooseAppearance() = 0; + virtual IReGameHookRegistry_HandleMenu_ChooseTeam* HandleMenu_ChooseTeam() = 0; + virtual IReGameHookRegistry_ShowMenu* ShowMenu() = 0; + virtual IReGameHookRegistry_ShowVGUIMenu* ShowVGUIMenu() = 0; + + virtual IReGameHookRegistry_CSGameRules_FShouldSwitchWeapon* CSGameRules_FShouldSwitchWeapon() = 0; + virtual IReGameHookRegistry_CSGameRules_GetNextBestWeapon* CSGameRules_GetNextBestWeapon() = 0; + virtual IReGameHookRegistry_CSGameRules_FlPlayerFallDamage* CSGameRules_FlPlayerFallDamage() = 0; + virtual IReGameHookRegistry_CSGameRules_FPlayerCanTakeDamage* CSGameRules_FPlayerCanTakeDamage() = 0; + virtual IReGameHookRegistry_CSGameRules_PlayerSpawn* CSGameRules_PlayerSpawn() = 0; + virtual IReGameHookRegistry_CSGameRules_FPlayerCanRespawn* CSGameRules_FPlayerCanRespawn() = 0; + virtual IReGameHookRegistry_CSGameRules_GetPlayerSpawnSpot* CSGameRules_GetPlayerSpawnSpot() = 0; + virtual IReGameHookRegistry_CSGameRules_ClientUserInfoChanged* CSGameRules_ClientUserInfoChanged() = 0; + virtual IReGameHookRegistry_CSGameRules_PlayerKilled* CSGameRules_PlayerKilled() = 0; + virtual IReGameHookRegistry_CSGameRules_DeathNotice* CSGameRules_DeathNotice() = 0; + virtual IReGameHookRegistry_CSGameRules_CanHavePlayerItem* CSGameRules_CanHavePlayerItem() = 0; + virtual IReGameHookRegistry_CSGameRules_DeadPlayerWeapons* CSGameRules_DeadPlayerWeapons() = 0; + virtual IReGameHookRegistry_CSGameRules_ServerDeactivate* CSGameRules_ServerDeactivate() = 0; + virtual IReGameHookRegistry_CSGameRules_CheckMapConditions* CSGameRules_CheckMapConditions() = 0; + virtual IReGameHookRegistry_CSGameRules_CleanUpMap* CSGameRules_CleanUpMap() = 0; + virtual IReGameHookRegistry_CSGameRules_RestartRound* CSGameRules_RestartRound() = 0; + virtual IReGameHookRegistry_CSGameRules_CheckWinConditions* CSGameRules_CheckWinConditions() = 0; + virtual IReGameHookRegistry_CSGameRules_RemoveGuns* CSGameRules_RemoveGuns() = 0; + virtual IReGameHookRegistry_CSGameRules_GiveC4* CSGameRules_GiveC4() = 0; + virtual IReGameHookRegistry_CSGameRules_ChangeLevel* CSGameRules_ChangeLevel() = 0; + virtual IReGameHookRegistry_CSGameRules_GoToIntermission* CSGameRules_GoToIntermission() = 0; + virtual IReGameHookRegistry_CSGameRules_BalanceTeams* CSGameRules_BalanceTeams() = 0; +}; + +struct ReGameFuncs_t { + class CBasePlayer *(*UTIL_PlayerByIndex)(int playerIndex); + struct edict_s *(*CREATE_NAMED_ENTITY2)(string_t iClass); + void (*ChangeString)(char *&dest, const char *source); + void (*RadiusDamage)(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType); + void (*ClearMultiDamage)(); + void (*ApplyMultiDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker); + void (*AddMultiDamage)(entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType); + class CBaseEntity *(*UTIL_FindEntityByString)(class CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue); +}; + +class IReGameApi { +public: + virtual ~IReGameApi() {} + + virtual int GetMajorVersion() = 0; + virtual int GetMinorVersion() = 0; + virtual const ReGameFuncs_t* GetFuncs() = 0; + virtual IReGameHookchains* GetHookchains() = 0; + + virtual class CGameRules* GetGameRules() = 0; + virtual struct WeaponInfoStruct* GetWeaponInfo(int weaponID) = 0; + virtual struct WeaponInfoStruct* GetWeaponInfo(const char* weaponName) = 0; + virtual struct playermove_s* GetPlayerMove() = 0; + virtual struct WeaponSlotInfo* GetWeaponSlot(WeaponIdType weaponID) = 0; + virtual struct WeaponSlotInfo* GetWeaponSlot(const char* weaponName) = 0; +}; + +#define VRE_GAMEDLL_API_VERSION "VRE_GAMEDLL_API_VERSION001" diff --git a/metamod/include/dlls/regamedll_common.h b/metamod/include/dlls/regamedll_common.h new file mode 100644 index 0000000..638d5dc --- /dev/null +++ b/metamod/include/dlls/regamedll_common.h @@ -0,0 +1,95 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#ifndef _WIN32 +#define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]); +#endif + +#define Q_isspace isspace +#define Q_isalnum isalnum +#define Q_isalpha isalpha + +#define Q_malloc malloc +#define Q_calloc calloc +#define Q_alloca alloca +#define Q_free free + +#define Q_min min +#define Q_max max +#define Q_clamp clamp +#define Q_access _access +#define Q_close _close +#define Q_write _write +#define Q_memset memset +#define Q_memcpy memcpy +#define Q_strlen strlen +#define Q_memcmp memcmp +#define Q_strcpy strcpy +#define Q_strncpy strncpy +#define Q_strrchr strrchr +#define Q_strcat strcat +#define Q_strncat strncat +#define Q_strcmp strcmp +#define Q_strncmp strncmp +#define Q_sscanf sscanf +#define Q_strdup _strdup +#define Q_stricmp _stricmp +#define Q_strnicmp _strnicmp +#define Q_strstr strstr +#define Q_strchr strchr +#define Q_strrchr strrchr +#define Q_strlwr _strlwr +#define Q_sprintf sprintf +#define Q_snprintf _snprintf +#define Q_atoi atoi +#define Q_atof atof +#define Q_toupper toupper +#define Q_memmove memmove +#define Q_vsnprintf _vsnprintf +#define Q_vsnwprintf _vsnwprintf +#define Q_abs abs +#define Q_fabs fabs +#define Q_tan tan +#define Q_atan atan +#define Q_atan2 atan2 +#define Q_acos acos +#define Q_cos cos +#define Q_sin sin +#define Q_pow pow +#define Q_fmod fmod +#define Q_fopen fopen +#define Q_fprintf fprintf +#define Q_fclose fclose + +#ifdef REGAMEDLL_FIXES +#define Q_sqrt M_sqrt +#else +#define Q_sqrt sqrt +#endif diff --git a/metamod/include/dlls/regamedll_const.h b/metamod/include/dlls/regamedll_const.h new file mode 100644 index 0000000..36d038b --- /dev/null +++ b/metamod/include/dlls/regamedll_const.h @@ -0,0 +1,104 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) +#define FCAP_CUSTOMSAVE 0x00000001 +#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions +#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore +#define FCAP_DONT_SAVE 0x80000000 // Don't save this +#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player +#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player +#define FCAP_ONOFF_USE 0x00000020 // can be used by the player +#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) +#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource) + +// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! +#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions + +// for Classify +#define CLASS_NONE 0 +#define CLASS_MACHINE 1 +#define CLASS_PLAYER 2 +#define CLASS_HUMAN_PASSIVE 3 +#define CLASS_HUMAN_MILITARY 4 +#define CLASS_ALIEN_MILITARY 5 +#define CLASS_ALIEN_PASSIVE 6 +#define CLASS_ALIEN_MONSTER 7 +#define CLASS_ALIEN_PREY 8 +#define CLASS_ALIEN_PREDATOR 9 +#define CLASS_INSECT 10 +#define CLASS_PLAYER_ALLY 11 +#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players +#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace +#define CLASS_VEHICLE 14 +#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. + +#define SF_NORESPAWN (1 << 30) // set this bit on guns and stuff that should never respawn. + +#define DMG_GENERIC 0 // generic damage was done +#define DMG_CRUSH (1<<0) // crushed by falling or moving object +#define DMG_BULLET (1<<1) // shot +#define DMG_SLASH (1<<2) // cut, clawed, stabbed +#define DMG_BURN (1<<3) // heat burned +#define DMG_FREEZE (1<<4) // frozen +#define DMG_FALL (1<<5) // fell too far +#define DMG_BLAST (1<<6) // explosive blast damage +#define DMG_CLUB (1<<7) // crowbar, punch, headbutt +#define DMG_SHOCK (1<<8) // electric shock +#define DMG_SONIC (1<<9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1<<10) // laser or other high energy beam +#define DMG_NEVERGIB (1<<12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1<<13) // with this bit OR'd in, any damage type can be made to gib victims upon death +#define DMG_DROWN (1<<14) // Drowning + +// time-based damage +#define DMG_TIMEBASED (~(0x3FFF)) // mask for time-based damage + +#define DMG_PARALYZE (1<<15) // slows affected creature down +#define DMG_NERVEGAS (1<<16) // nerve toxins, very bad +#define DMG_POISON (1<<17) // blood poisioning +#define DMG_RADIATION (1<<18) // radiation exposure +#define DMG_DROWNRECOVER (1<<19) // drowning recovery +#define DMG_ACID (1<<20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1<<21) // in an oven +#define DMG_SLOWFREEZE (1<<22) // in a subzero freezer +#define DMG_MORTAR (1<<23) // Hit by air raid (done to distinguish grenade from mortar) +#define DMG_EXPLOSION (1<<24) + +// these are the damage types that are allowed to gib corpses +#define DMG_GIB_CORPSE (DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB) + +// these are the damage types that have client hud art +#define DMG_SHOWNHUD (DMG_POISON | DMG_ACID | DMG_FREEZE | DMG_SLOWFREEZE | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK) + +// when calling KILLED(), a value that governs gib behavior is expected to be +// one of these three values +#define GIB_NORMAL 0 // gib if entity was overkilled +#define GIB_NEVER 1 // never gib, no matter how much death damage is done ( freezing, etc ) +#define GIB_ALWAYS 2 // always gib ( Houndeye Shock, Barnacle Bite ) diff --git a/metamod/include/dlls/regamedll_interfaces.h b/metamod/include/dlls/regamedll_interfaces.h new file mode 100644 index 0000000..84a749f --- /dev/null +++ b/metamod/include/dlls/regamedll_interfaces.h @@ -0,0 +1,296 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class CBaseEntity; +class CBasePlayer; + +// Implementation wrapper +class CCSEntity { +public: + virtual ~CCSEntity() {} + virtual void FireBullets(int iShots, Vector &vecSrc, Vector &vecDirShooting, Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker); + virtual Vector FireBullets3(Vector &vecSrc, Vector &vecDirShooting, float vecSpread, float flDistance, int iPenetration, int iBulletType, int iDamage, float flRangeModifier, entvars_t *pevAttacker, bool bPistol, int shared_rand); +public: + CBaseEntity *m_pContainingEntity; +}; + +class CCSDelay: public CCSEntity {}; +class CCSAnimating: public CCSDelay {}; +class CCSPlayerItem: public CCSAnimating {}; +class CCSToggle: public CCSAnimating {}; +class CCSMonster: public CCSToggle {}; +class CCSWeaponBox: public CCSEntity {}; +class CCSArmoury: public CCSEntity {}; + +class CCSPlayer: public CCSMonster { +public: + CCSPlayer() : m_bForceShowMenu(false) + { + m_szModel[0] = '\0'; + } + + virtual bool IsConnected() const; + virtual void SetAnimation(PLAYER_ANIM playerAnim); + virtual void AddAccount(int amount, RewardType type = RT_NONE, bool bTrackChange = true); + virtual void GiveNamedItem(const char *pszName); + virtual void GiveNamedItemEx(const char *pszName); + virtual void GiveDefaultItems(); + virtual void GiveShield(bool bDeploy = true); + virtual void DropShield(bool bDeploy = true); + virtual void DropPlayerItem(const char *pszItemName); + virtual void RemoveShield(); + virtual void RemoveAllItems(bool bRemoveSuit); + virtual bool RemovePlayerItem(const char* pszItemName); + virtual void SetPlayerModel(bool bHasC4); + virtual void SetPlayerModelEx(const char *modelName); + virtual void SetNewPlayerModel(const char *modelName); + virtual void ClientCommand(const char *cmd, const char *arg1 = nullptr, const char *arg2 = nullptr, const char *arg3 = nullptr); + virtual void SetProgressBarTime(int time); + virtual void SetProgressBarTime2(int time, float timeElapsed); + virtual struct edict_s *EntSelectSpawnPoint(); + virtual void SetBombIcon(bool bFlash = false); + virtual void SetScoreAttrib(CBasePlayer *dest); + virtual void SendItemStatus(); + virtual void ReloadWeapons(CBasePlayerItem *pWeapon = nullptr, bool bForceReload = false, bool bForceRefill = false); + virtual void Observer_SetMode(int iMode); + virtual bool SelectSpawnSpot(const char *pEntClassName, CBaseEntity* &pSpot); + virtual bool SwitchWeapon(CBasePlayerItem *pWeapon); + virtual void SwitchTeam(); + virtual bool JoinTeam(TeamName team); + virtual void StartObserver(Vector& vecPosition, Vector& vecViewAngle); + virtual void TeamChangeUpdate(); + virtual void DropSecondary(); + virtual void DropPrimary(); + virtual bool HasPlayerItem(CBasePlayerItem *pCheckItem); + virtual bool HasNamedPlayerItem(const char *pszItemName); + + CBasePlayer *BasePlayer() const; +public: + char m_szModel[32]; + bool m_bForceShowMenu; +}; + +class CAPI_Bot: public CCSPlayer {}; +class CAPI_CSBot: public CAPI_Bot {}; +class CCSShield: public CCSEntity {}; +class CCSDeadHEV: public CCSMonster {}; +class CCSSprayCan: public CCSEntity {}; +class CCSBloodSplat: public CCSEntity {}; +class CCSPlayerWeapon: public CCSPlayerItem {}; +class CCSWorld: public CCSEntity {}; +class CCSDecal: public CCSEntity {}; +class CCSCorpse: public CCSEntity {}; +class CCSGrenade: public CCSMonster {}; +class CCSAirtank: public CCSGrenade {}; +class CCSPlayerAmmo: public CCSEntity {}; +class CCS9MMAmmo: public CCSPlayerAmmo {}; +class CCSBuckShotAmmo: public CCSPlayerAmmo {}; +class CCS556NatoAmmo: public CCSPlayerAmmo {}; +class CCS556NatoBoxAmmo: public CCSPlayerAmmo {}; +class CCS762NatoAmmo: public CCSPlayerAmmo {}; +class CCS45ACPAmmo: public CCSPlayerAmmo {}; +class CCS50AEAmmo: public CCSPlayerAmmo {}; +class CCS338MagnumAmmo: public CCSPlayerAmmo {}; +class CCS57MMAmmo: public CCSPlayerAmmo {}; +class CCS357SIGAmmo: public CCSPlayerAmmo {}; +class CCSFuncWall: public CCSEntity {}; +class CCSFuncWallToggle: public CCSFuncWall {}; +class CCSFuncConveyor: public CCSFuncWall {}; +class CCSFuncIllusionary: public CCSToggle {}; +class CCSFuncMonsterClip: public CCSFuncWall {}; +class CCSFuncRotating: public CCSEntity {}; +class CCSPendulum: public CCSEntity {}; +class CCSPointEntity: public CCSEntity {}; +class CCSStripWeapons: public CCSPointEntity {}; +class CCSInfoIntermission: public CCSPointEntity {}; +class CCSRevertSaved: public CCSPointEntity {}; +class CCSEnvGlobal: public CCSPointEntity {}; +class CCSMultiSource: public CCSPointEntity {}; +class CCSButton: public CCSToggle {}; +class CCSRotButton: public CCSButton {}; +class CCSMomentaryRotButton: public CCSToggle {}; +class CCSEnvSpark: public CCSEntity {}; +class CCSButtonTarget: public CCSEntity {}; +class CCSDoor: public CCSToggle {}; +class CCSRotDoor: public CCSDoor {}; +class CCSMomentaryDoor: public CCSToggle {}; +class CCSGib: public CCSEntity {}; +class CCSBubbling: public CCSEntity {}; +class CCSBeam: public CCSEntity {}; +class CCSLightning: public CCSBeam {}; +class CCSLaser: public CCSBeam {}; +class CCSGlow: public CCSPointEntity {}; +class CCSSprite: public CCSPointEntity {}; +class CCSBombGlow: public CCSSprite {}; +class CCSGibShooter: public CCSDelay {}; +class CCSEnvShooter: public CCSGibShooter {}; +class CCSTestEffect: public CCSDelay {}; +class CCSBlood: public CCSPointEntity {}; +class CCSShake: public CCSPointEntity {}; +class CCSFade: public CCSPointEntity {}; +class CCSMessage: public CCSPointEntity {}; +class CCSEnvFunnel: public CCSDelay {}; +class CCSEnvBeverage: public CCSDelay {}; +class CCSItemSoda: public CCSEntity {}; +class CCSShower: public CCSEntity {}; +class CCSEnvExplosion: public CCSMonster {}; +class CCSBreakable: public CCSDelay {}; +class CCSPushable: public CCSBreakable {}; +class CCSFuncTank: public CCSEntity {}; +class CCSFuncTankGun: public CCSFuncTank {}; +class CCSFuncTankLaser: public CCSFuncTank {}; +class CCSFuncTankRocket: public CCSFuncTank {}; +class CCSFuncTankMortar: public CCSFuncTank {}; +class CCSFuncTankControls: public CCSEntity {}; +class CCSRecharge: public CCSToggle {}; +class CCSCycler: public CCSMonster {}; +class CCSGenericCycler: public CCSCycler {}; +class CCSCyclerProbe: public CCSCycler {}; +class CCSCyclerSprite: public CCSEntity {}; +class CCSWeaponCycler: public CCSPlayerWeapon {}; +class CCSWreckage: public CCSMonster {}; +class CCSWorldItem: public CCSEntity {}; +class CCSItem: public CCSEntity {}; +class CCSHealthKit: public CCSItem {}; +class CCSWallHealth: public CCSToggle {}; +class CCSItemSuit: public CCSItem {}; +class CCSItemBattery: public CCSItem {}; +class CCSItemAntidote: public CCSItem {}; +class CCSItemSecurity: public CCSItem {}; +class CCSItemLongJump: public CCSItem {}; +class CCSItemKevlar: public CCSItem {}; +class CCSItemAssaultSuit: public CCSItem {}; +class CCSItemThighPack: public CCSItem {}; +class CCSGrenCatch: public CCSEntity {}; +class CCSFuncWeaponCheck: public CCSEntity {}; +class CCSHostage: public CCSMonster {}; +class CCSLight: public CCSPointEntity {}; +class CCSEnvLight: public CCSLight {}; +class CCSRuleEntity: public CCSEntity {}; +class CCSRulePointEntity: public CCSRuleEntity {}; +class CCSRuleBrushEntity: public CCSRuleEntity {}; +class CCSGameScore: public CCSRulePointEntity {}; +class CCSGameEnd: public CCSRulePointEntity {}; +class CCSGameText: public CCSRulePointEntity {}; +class CCSGameTeamMaster: public CCSRulePointEntity {}; +class CCSGameTeamSet: public CCSRulePointEntity {}; +class CCSGamePlayerZone: public CCSRuleBrushEntity {}; +class CCSGamePlayerHurt: public CCSRulePointEntity {}; +class CCSGameCounter: public CCSRulePointEntity {}; +class CCSGameCounterSet: public CCSRulePointEntity {}; +class CCSGamePlayerEquip: public CCSRulePointEntity {}; +class CCSGamePlayerTeam: public CCSRulePointEntity {}; +class CCSFuncMortarField: public CCSToggle {}; +class CCSMortar: public CCSGrenade {}; +class CCSMapInfo: public CCSPointEntity {}; +class CCSPathCorner: public CCSPointEntity {}; +class CCSPathTrack: public CCSPointEntity {}; +class CCSFuncTrackTrain: public CCSEntity {}; +class CCSFuncVehicleControls: public CCSEntity {}; +class CCSFuncVehicle: public CCSEntity {}; +class CCSPlatTrain: public CCSToggle {}; +class CCSFuncPlat: public CCSPlatTrain {}; +class CCSPlatTrigger: public CCSEntity {}; +class CCSFuncPlatRot: public CCSFuncPlat {}; +class CCSFuncTrain: public CCSPlatTrain {}; +class CCSFuncTrainControls: public CCSEntity {}; +class CCSFuncTrackChange: public CCSFuncPlatRot {}; +class CCSFuncTrackAuto: public CCSFuncTrackChange {}; +class CCSGunTarget: public CCSMonster {}; +class CCSAmbientGeneric: public CCSEntity {}; +class CCSEnvSound: public CCSPointEntity {}; +class CCSSpeaker: public CCSEntity {}; +class CCSSoundEnt: public CCSEntity {}; +class CCSUSP: public CCSPlayerWeapon {}; +class CCSMP5N: public CCSPlayerWeapon {}; +class CCSSG552: public CCSPlayerWeapon {}; +class CCSAK47: public CCSPlayerWeapon {}; +class CCSAUG: public CCSPlayerWeapon {}; +class CCSAWP: public CCSPlayerWeapon {}; +class CCSC4: public CCSPlayerWeapon {}; +class CCSDEAGLE: public CCSPlayerWeapon {}; +class CCSFlashbang: public CCSPlayerWeapon {}; +class CCSG3SG1: public CCSPlayerWeapon {}; +class CCSGLOCK18: public CCSPlayerWeapon {}; +class CCSHEGrenade: public CCSPlayerWeapon {}; +class CCSKnife: public CCSPlayerWeapon {}; +class CCSM249: public CCSPlayerWeapon {}; +class CCSM3: public CCSPlayerWeapon {}; +class CCSM4A1: public CCSPlayerWeapon {}; +class CCSMAC10: public CCSPlayerWeapon {}; +class CCSP228: public CCSPlayerWeapon {}; +class CCSP90: public CCSPlayerWeapon {}; +class CCSSCOUT: public CCSPlayerWeapon {}; +class CCSSmokeGrenade: public CCSPlayerWeapon {}; +class CCSTMP: public CCSPlayerWeapon {}; +class CCSXM1014: public CCSPlayerWeapon {}; +class CCSELITE: public CCSPlayerWeapon {}; +class CCSFiveSeven: public CCSPlayerWeapon {}; +class CCSUMP45: public CCSPlayerWeapon {}; +class CCSSG550: public CCSPlayerWeapon {}; +class CCSGalil: public CCSPlayerWeapon {}; +class CCSFamas: public CCSPlayerWeapon {}; +class CCSNullEntity: public CCSEntity {}; +class CCSDMStart: public CCSPointEntity {}; +class CCSFrictionModifier: public CCSEntity {}; +class CCSAutoTrigger: public CCSDelay {}; +class CCSTriggerRelay: public CCSDelay {}; +class CCSMultiManager: public CCSToggle {}; +class CCSRenderFxManager: public CCSEntity {}; +class CCSTrigger: public CCSToggle {}; +class CCSTriggerHurt: public CCSTrigger {}; +class CCSTriggerMonsterJump: public CCSTrigger {}; +class CCSTriggerCDAudio: public CCSTrigger {}; +class CCSTargetCDAudio: public CCSPointEntity {}; +class CCSTriggerMultiple: public CCSTrigger {}; +class CCSTriggerOnce: public CCSTriggerMultiple {}; +class CCSTriggerCounter: public CCSTrigger {}; +class CCSTriggerVolume: public CCSPointEntity {}; +class CCSFireAndDie: public CCSDelay {}; +class CCSChangeLevel: public CCSTrigger {}; +class CCSLadder: public CCSTrigger {}; +class CCSTriggerPush: public CCSTrigger {}; +class CCSTriggerTeleport: public CCSTrigger {}; +class CCSBuyZone: public CCSTrigger {}; +class CCSBombTarget: public CCSTrigger {}; +class CCSHostageRescue: public CCSTrigger {}; +class CCSEscapeZone: public CCSTrigger {}; +class CCSVIP_SafetyZone: public CCSTrigger {}; +class CCSTriggerSave: public CCSTrigger {}; +class CCSTriggerEndSection: public CCSTrigger {}; +class CCSTriggerGravity: public CCSTrigger {}; +class CCSTriggerChangeTarget: public CCSDelay {}; +class CCSTriggerCamera: public CCSDelay {}; +class CCSWeather: public CCSTrigger {}; +class CCSClientFog: public CCSEntity {}; + +inline CBasePlayer *CCSPlayer::BasePlayer() const { + return reinterpret_cast(this->m_pContainingEntity); +} diff --git a/metamod/include/dlls/revert_saved.h b/metamod/include/dlls/revert_saved.h new file mode 100644 index 0000000..f8bb4ee --- /dev/null +++ b/metamod/include/dlls/revert_saved.h @@ -0,0 +1,49 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CRevertSaved: public CPointEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float Duration() const { return pev->dmg_take; } + float HoldTime() const { return pev->dmg_save; } + float MessageTime() const { return m_messageTime; } + float LoadTime() const { return m_loadTime; } + + void SetDuration(float duration) { pev->dmg_take = duration; } + void SetHoldTime(float hold) { pev->dmg_save = hold; } + void SetMessageTime(float time) { m_messageTime = time; } + void SetLoadTime(float time) { m_loadTime = time; } +public: + float m_messageTime; + float m_loadTime; +}; diff --git a/metamod/include/dlls/skill.h b/metamod/include/dlls/skill.h new file mode 100644 index 0000000..95e2084 --- /dev/null +++ b/metamod/include/dlls/skill.h @@ -0,0 +1,53 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 + +struct skilldata_t +{ + int iSkillLevel; + float plrDmg9MM; + float plrDmg357; + float plrDmgMP5; + float plrDmgM203Grenade; + float plrDmgBuckshot; + float plrDmgCrossbowClient; + float plrDmgRPG; + float monDmg9MM; + float monDmgMP5; + float monDmg12MM; + float suitchargerCapacity; + float batteryCapacity; + float healthchargerCapacity; + float healthkitCapacity; +}; + +extern skilldata_t gSkillData; diff --git a/metamod/include/dlls/sound.h b/metamod/include/dlls/sound.h new file mode 100644 index 0000000..c4e636c --- /dev/null +++ b/metamod/include/dlls/sound.h @@ -0,0 +1,141 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define CSENTENCEG_MAX 200 // max number of sentence groups +#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group +#define CDPVPRESETMAX 27 + +// spawnflags +#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation +#define AMBIENT_SOUND_EVERYWHERE 1 +#define AMBIENT_SOUND_SMALLRADIUS 2 +#define AMBIENT_SOUND_MEDIUMRADIUS 4 +#define AMBIENT_SOUND_LARGERADIUS 8 +#define AMBIENT_SOUND_START_SILENT 16 +#define AMBIENT_SOUND_NOT_LOOPING 32 + +#define ANNOUNCE_MINUTES_MIN 0.25 +#define ANNOUNCE_MINUTES_MAX 2.25 + +#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements + +#define LFO_SQUARE 1 // square +#define LFO_TRIANGLE 2 // triangle +#define LFO_RANDOM 3 // random + +// group of related sentences +struct sentenceg +{ + char szgroupname[16]; + int count; + unsigned char rgblru[ CSENTENCE_LRU_MAX ]; +}; + +// runtime pitch shift and volume fadein/out structure + +// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER +// SEE BELOW (in the typedescription for the class) +typedef struct dynpitchvol +{ + // NOTE: do not change the order of these parameters + // NOTE: unless you also change order of rgdpvpreset array elements! + int preset; + + int pitchrun; // pitch shift % when sound is running 0 - 255 + int pitchstart; // pitch shift % when sound stops or starts 0 - 255 + int spinup; // spinup time 0 - 100 + int spindown; // spindown time 0 - 100 + + int volrun; // volume change % when sound is running 0 - 10 + int volstart; // volume change % when sound stops or starts 0 - 10 + int fadein; // volume fade in time 0 - 100 + int fadeout; // volume fade out time 0 - 100 + + // Low Frequency Oscillator + int lfotype; // 0) off 1) square 2) triangle 3) random + int lforate; // 0 - 1000, how fast lfo osciallates + + int lfomodpitch; // 0-100 mod of current pitch. 0 is off. + int lfomodvol; // 0-100 mod of current volume. 0 is off. + + int cspinup; // each trigger hit increments counter and spinup pitch + + int cspincount; + int pitch; + int spinupsav; + int spindownsav; + int pitchfrac; + int vol; + int fadeinsav; + int fadeoutsav; + int volfrac; + int lfofrac; + int lfomult; + +} dynpitchvol_t; + +class CAmbientGeneric: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; +public: + float m_flAttenuation; // attenuation value + dynpitchvol_t m_dpv; + BOOL m_fActive; // only TRUE when the entity is playing a looping sound + BOOL m_fLooping; // TRUE when the sound played will loop +}; + +class CEnvSound: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Think() = 0; +public: + float m_flRadius; + float m_flRoomtype; +}; + +class CSpeaker: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; +public: + int m_preset; // preset number +}; diff --git a/metamod/include/dlls/spectator.h b/metamod/include/dlls/spectator.h new file mode 100644 index 0000000..d42e05a --- /dev/null +++ b/metamod/include/dlls/spectator.h @@ -0,0 +1,33 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CBaseSpectator: public CBaseEntity { +public: + virtual void Spawn(); +}; diff --git a/metamod/include/dlls/subs.h b/metamod/include/dlls/subs.h new file mode 100644 index 0000000..8cae347 --- /dev/null +++ b/metamod/include/dlls/subs.h @@ -0,0 +1,40 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +class CNullEntity: public CBaseEntity { +public: + virtual void Spawn() = 0; +}; + +class CBaseDMStart: public CPointEntity { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual BOOL IsTriggered(CBaseEntity *pEntity) = 0; +}; diff --git a/metamod/include/dlls/training_gamerules.h b/metamod/include/dlls/training_gamerules.h new file mode 100644 index 0000000..079e2be --- /dev/null +++ b/metamod/include/dlls/training_gamerules.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CHalfLifeTraining: public CHalfLifeMultiplay { +protected: + virtual ~CHalfLifeTraining() {}; +public: + virtual BOOL IsMultiplayer() = 0; + virtual BOOL IsDeathmatch() = 0; + virtual void InitHUD(CBasePlayer *pl) = 0; + virtual void PlayerSpawn(CBasePlayer *pPlayer) = 0; + virtual void PlayerThink(CBasePlayer *pPlayer) = 0; + virtual BOOL FPlayerCanRespawn(CBasePlayer *pPlayer) = 0; + virtual edict_t *GetPlayerSpawnSpot(CBasePlayer *pPlayer) = 0; + virtual void PlayerKilled(CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor) = 0; + virtual int ItemShouldRespawn(CItem *pItem) = 0; + virtual void CheckMapConditions() = 0; + virtual void CheckWinConditions() = 0; +public: + float FillAccountTime; + float ServerRestartTime; + BOOL fInBuyArea; + BOOL fVisitedBuyArea; + bool fVGUIMenus; +}; + +class CBaseGrenCatch: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Think() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +public: + int m_NeedGrenadeType; + string_t sTriggerOnGrenade; + string_t sDisableOnGrenade; + bool m_fSmokeTouching; + bool m_fFlashTouched; +}; + +class CFuncWeaponCheck: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +private: + string_t sTriggerWithItems; + string_t sTriggerNoItems; + string_t sMaster; + unsigned int sItemName[32]; + int iItemCount; + int iAnyWeapon; +}; diff --git a/metamod/include/dlls/trains.h b/metamod/include/dlls/trains.h new file mode 100644 index 0000000..10927b6 --- /dev/null +++ b/metamod/include/dlls/trains.h @@ -0,0 +1,149 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// Tracktrain spawn flags +#define SF_TRACKTRAIN_NOPITCH 0x0001 +#define SF_TRACKTRAIN_NOCONTROL 0x0002 +#define SF_TRACKTRAIN_FORWARDONLY 0x0004 +#define SF_TRACKTRAIN_PASSABLE 0x0008 + +// Spawnflag for CPathTrack +#define SF_PATH_DISABLED 0x00000001 +#define SF_PATH_FIREONCE 0x00000002 +#define SF_PATH_ALTREVERSE 0x00000004 +#define SF_PATH_DISABLE_TRAIN 0x00000008 +#define SF_PATH_ALTERNATE 0x00008000 + +// Spawnflags of CPathCorner +#define SF_CORNER_WAITFORTRIG 0x001 +#define SF_CORNER_TELEPORT 0x002 +#define SF_CORNER_FIREONCE 0x004 + +class CPathTrack: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData* pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void Activate() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + float m_length; + string_t m_altName; + CPathTrack *m_pnext; + CPathTrack *m_pprevious; + CPathTrack *m_paltpath; +}; + +class CFuncTrackTrain: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData* pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void OverrideReset() = 0; + virtual BOOL OnControls(entvars_t *pev) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + CPathTrack *m_ppath; + float m_length; + float m_height; + float m_speed; + float m_dir; + float m_startSpeed; + Vector m_controlMins; + Vector m_controlMaxs; + int m_soundPlaying; + int m_sounds; + float m_flVolume; + float m_flBank; + float m_oldSpeed; + float m_fTurnAngle; + float m_flSteeringWheelDecay; + float m_flAcceleratorDecay; + +private: + unsigned short m_usAdjustPitch; +}; + +class CFuncVehicle: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual int Classify() = 0; + virtual void OverrideReset() = 0; + virtual BOOL OnControls(entvars_t *pev) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void Blocked(CBaseEntity *pOther) = 0; +public: + CPathTrack *m_ppath; + float m_length; + float m_width; + float m_height; + float m_speed; + float m_dir; + float m_startSpeed; + Vector m_controlMins; + Vector m_controlMaxs; + int m_soundPlaying; + int m_sounds; + int m_acceleration; + float m_flVolume; + float m_flBank; + float m_oldSpeed; + int m_iTurnAngle; + float m_flSteeringWheelDecay; + float m_flAcceleratorDecay; + float m_flTurnStartTime; + float m_flLaunchTime; + float m_flLastNormalZ; + float m_flCanTurnNow; + float m_flUpdateSound; + Vector m_vFrontLeft; + Vector m_vFront; + Vector m_vFrontRight; + Vector m_vBackLeft; + Vector m_vBack; + Vector m_vBackRight; + Vector m_vSurfaceNormal; + Vector m_vVehicleDirection; + CBaseEntity *m_pDriver; + +private: + unsigned short m_usAdjustPitch; +}; diff --git a/metamod/include/dlls/triggers.h b/metamod/include/dlls/triggers.h new file mode 100644 index 0000000..3e87253 --- /dev/null +++ b/metamod/include/dlls/triggers.h @@ -0,0 +1,358 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define GRENADETYPE_SMOKE 1 +#define GRENADETYPE_FLASH 2 + +#define MAX_ITEM_COUNTS 32 +#define MAX_ENTITY 512 // We can only ever move 512 entities across a transition + +// triggers +#define SF_TRIGGER_ALLOWMONSTERS 1 // monsters allowed to fire this trigger +#define SF_TRIGGER_NOCLIENTS 2 // players not allowed to fire this trigger +#define SF_TRIGGER_PUSHABLES 4 // only pushables can fire this trigger + +#define SF_TRIGGER_PUSH_START_OFF 2 // spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_TARGETONCE 1 // Only fire hurt target once +#define SF_TRIGGER_HURT_START_OFF 2 // spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_NO_CLIENTS 8 // spawnflag that makes trigger_push spawn turned OFF +#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16 // trigger hurt will only fire its target if it is hurting a client +#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32 // only clients may touch this trigger. + +#define SF_AUTO_FIREONCE 0x0001 +#define SF_RELAY_FIREONCE 0x0001 +#define SF_ENDSECTION_USEONLY 0x0001 + +#define SF_MULTIMAN_CLONE 0x80000000 +#define SF_MULTIMAN_THREAD 0x00000001 + +#define SF_CHANGELEVEL_USEONLY 0x0002 +#define SF_CAMERA_PLAYER_POSITION 1 +#define SF_CAMERA_PLAYER_TARGET 2 +#define SF_CAMERA_PLAYER_TAKECONTROL 4 + +// Flags to indicate masking off various render parameters that are normally copied to the targets +#define SF_RENDER_MASKFX (1 << 0) +#define SF_RENDER_MASKAMT (1 << 1) +#define SF_RENDER_MASKMODE (1 << 2) +#define SF_RENDER_MASKCOLOR (1 << 3) + +class CFrictionModifier: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; +public: + float m_frictionFraction; +}; + +// This trigger will fire when the level spawns (or respawns if not fire once) +// It will check a global state before firing. It supports delay and killtargets +class CAutoTrigger: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Think() = 0; +public: + int m_globalstate; + USE_TYPE triggerType; +}; + +class CTriggerRelay: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + USE_TYPE triggerType; +}; + +// The Multimanager Entity - when fired, will fire up to 16 targets +// at specified times. +// FLAG: THREAD (create clones when triggered) +// FLAG: CLONE (this is a clone for a threaded execution) +class CMultiManager: public CBaseToggle { +public: + virtual void Spawn() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual BOOL HasTarget(string_t targetname) = 0; +public: + int m_cTargets; + int m_index; + float m_startTime; + int m_iTargetName[MAX_MULTI_TARGETS]; + float m_flTargetDelay[MAX_MULTI_TARGETS]; +}; + +// Render parameters trigger +// +// This entity will copy its render parameters (renderfx, rendermode, rendercolor, renderamt) +// to its targets when triggered. +class CRenderFxManager: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +class CBaseTrigger: public CBaseToggle { +public: + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int ObjectCaps() = 0; +}; + +// trigger_hurt - hurts anything that touches it. if the trigger has a targetname, firing it will toggle state +// int gfToggleState = 0; // used to determine when all radiation trigger hurts have called 'RadiationThink' +class CTriggerHurt: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CTriggerMonsterJump: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void Think() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +}; + +// trigger_cdaudio - starts/stops cd audio tracks +class CTriggerCDAudio: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +// This plays a CD track when fired or when the player enters it's radius +class CTargetCDAudio: public CPointEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Think() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +}; + +// QUAKED trigger_multiple (.5 .5 .5) ? notouch +// Variable sized repeatable trigger. Must be targeted at one or more entities. +// If "health" is set, the trigger must be killed to activate each time. +// If "delay" is set, the trigger waits some time after activating before firing. +// "wait" : Seconds between triggerings. (.2 default) +// If notouch is set, the trigger is only fired by other entities, not by touching. +// NOTOUCH has been obsoleted by trigger_relay! +// sounds +// 1) secret +// 2) beep beep +// 3) large switch +// 4) +// NEW +// if a trigger has a NETNAME, that NETNAME will become the TARGET of the triggered object. +class CTriggerMultiple: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +// QUAKED trigger_once (.5 .5 .5) ? notouch +// Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching +// "targetname". If "health" is set, the trigger must be killed to activate. +// If notouch is set, the trigger is only fired by other entities, not by touching. +// if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. +// if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. +// sounds +// 1) secret +// 2) beep beep +// 3) large switch +// 4) +class CTriggerOnce: public CTriggerMultiple { +public: + virtual void Spawn() = 0; +}; + +// QUAKED trigger_counter (.5 .5 .5) ? nomessage +// Acts as an intermediary for an action that takes multiple inputs. +// If nomessage is not set, it will print "1 more.. " etc when triggered and +// "sequence complete" when finished. After the counter has been triggered "cTriggersLeft" +// times (default 2), it will fire all of it's targets and remove itself. +class CTriggerCounter: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +// Derive from point entity so this doesn't move across levels +class CTriggerVolume: public CPointEntity { +public: + virtual void Spawn() = 0; +}; + +// Fires a target after level transition and then dies +class CFireAndDie: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int ObjectCaps() = 0; // Always go across transitions + virtual void Think() = 0; +}; + +// QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION +// When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. +class CChangeLevel: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; +public: + char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map + char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map + int m_changeTarget; + float m_changeTargetDelay; +}; + +class CLadder: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +}; + +class CTriggerPush: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +}; + +class CTriggerTeleport: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CBuyZone: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CBombTarget: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CHostageRescue: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CEscapeZone: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CVIP_SafetyZone: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CTriggerSave: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CTriggerEndSection: public CBaseTrigger { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +}; + +class CTriggerGravity: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +// this is a really bad idea. +class CTriggerChangeTarget: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +private: + int m_iszNewTarget; +}; + +class CTriggerCamera: public CBaseDelay { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; +public: + EHANDLE m_hPlayer; + EHANDLE m_hTarget; + CBaseEntity *m_pentPath; + int m_sPath; + float m_flWait; + float m_flReturnTime; + float m_flStopTime; + float m_moveDistance; + float m_targetSpeed; + float m_initialSpeed; + float m_acceleration; + float m_deceleration; + int m_state; +}; + +class CWeather: public CBaseTrigger { +public: + virtual void Spawn() = 0; +}; + +class CClientFog: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +public: + int m_iStartDist; + int m_iEndDist; + float m_fDensity; +}; diff --git a/metamod/include/dlls/unisignals.h b/metamod/include/dlls/unisignals.h new file mode 100644 index 0000000..054bdc5 --- /dev/null +++ b/metamod/include/dlls/unisignals.h @@ -0,0 +1,57 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef UNISIGNALS_H +#define UNISIGNALS_H +#ifdef _WIN32 +#pragma once +#endif + +class CUnifiedSignals +{ +public: + CUnifiedSignals() + { + m_flSignal = 0; + m_flState = 0; + } +public: + void Update() + { + m_flState = m_flSignal; + m_flSignal = 0; + } + void Signal(int flags) { m_flSignal |= flags; } + int GetSignal() const { return m_flSignal; } + int GetState() const { return m_flState; } +public: + int m_flSignal; + int m_flState; +}; + +#endif // UNISIGNALS_H diff --git a/metamod/include/dlls/util.h b/metamod/include/dlls/util.h new file mode 100644 index 0000000..e0d1d30 --- /dev/null +++ b/metamod/include/dlls/util.h @@ -0,0 +1,182 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "enginecallback.h" + +#define eoNullEntity 0 // Testing the three types of "entity" for nullity +#define iStringNull 0 // Testing strings for nullity + +#define cchMapNameMost 32 + +#define CBSENTENCENAME_MAX 16 +#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match CVOXFILESENTENCEMAX in engine\sound.h + +#define GROUP_OP_AND 0 +#define GROUP_OP_NAND 1 + +extern globalvars_t *gpGlobals; + +// Use this instead of ALLOC_STRING on constant strings +#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset))) +#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0))) + +// Dot products for view cone checking +#define VIEW_FIELD_FULL -1.0 // +-180 degrees +#define VIEW_FIELD_WIDE -0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks +#define VIEW_FIELD_NARROW 0.7 // +-45 degrees, more narrow check used to set up ranged attacks +#define VIEW_FIELD_ULTRA_NARROW 0.9 // +-25 degrees, more narrow check used to set up ranged attacks + +#define SND_SPAWNING (1<<8) // duplicated in protocol.h we're spawing, used in some cases for ambients +#define SND_STOP (1<<5) // duplicated in protocol.h stop sound +#define SND_CHANGE_VOL (1<<6) // duplicated in protocol.h change sound vol +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +// All monsters need this data +#define DONT_BLEED -1 +#define BLOOD_COLOR_RED (byte)247 +#define BLOOD_COLOR_YELLOW (byte)195 +#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW + +#define GERMAN_GIB_COUNT 4 +#define HUMAN_GIB_COUNT 6 +#define ALIEN_GIB_COUNT 4 + +#define LANGUAGE_ENGLISH 0 +#define LANGUAGE_GERMAN 1 +#define LANGUAGE_FRENCH 2 +#define LANGUAGE_BRITISH 3 + +#define SVC_TEMPENTITY 23 +#define SVC_INTERMISSION 30 +#define SVC_CDTRACK 32 +#define SVC_WEAPONANIM 35 +#define SVC_ROOMTYPE 37 +#define SVC_DIRECTOR 51 + +#define SF_TRIG_PUSH_ONCE 1 + +// func_rotating +#define SF_BRUSH_ROTATE_Y_AXIS 0 +#define SF_BRUSH_ROTATE_INSTANT 1 +#define SF_BRUSH_ROTATE_BACKWARDS 2 +#define SF_BRUSH_ROTATE_Z_AXIS 4 +#define SF_BRUSH_ROTATE_X_AXIS 8 +#define SF_PENDULUM_AUTO_RETURN 16 +#define SF_PENDULUM_PASSABLE 32 + +#define SF_BRUSH_ROTATE_SMALLRADIUS 128 +#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 +#define SF_BRUSH_ROTATE_LARGERADIUS 512 + +#define SPAWNFLAG_NOMESSAGE 1 +#define SPAWNFLAG_NOTOUCH 1 +#define SPAWNFLAG_DROIDONLY 4 + +#define VEC_HULL_MIN_Z Vector(0, 0, -36) +#define VEC_DUCK_HULL_MIN_Z Vector(0, 0, -18) + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_HULL_MAX Vector(16, 16, 36) + +#define VEC_VIEW Vector(0, 0, 17) + +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18) +#define VEC_DUCK_HULL_MAX Vector(16, 16, 32) +#define VEC_DUCK_VIEW Vector(0, 0, 12) + +#define PRECACHE_SOUND_ARRAY(a) \ + { for (int i = 0; i < ARRAYSIZE(a); ++i) PRECACHE_SOUND((char *)a[i]); } + +// Inlines +inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) { return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); } +inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) { return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); } + +inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } +inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } +inline EOFFSET OFFSET(const edict_t *pent) { return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); } +inline EOFFSET OFFSET(const entvars_t *pev) { return OFFSET(ENT(pev)); } + +inline entvars_t *VARS(edict_t *pent) +{ + if (!pent) + return NULL; + + return &pent->v; +} + +inline entvars_t *VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } +inline int ENTINDEX(const edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } +inline int ENTINDEX(const entvars_t *pev) { return (*g_engfuncs.pfnIndexOfEdict)(ENT(pev)); } +inline edict_t *INDEXENT(int iEdictNum) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } +inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent) { MESSAGE_BEGIN(msg_dest, msg_type, pOrigin, ENT(ent)); } +inline BOOL FNullEnt(EOFFSET eoffset) { return (eoffset == 0); } +inline BOOL FNullEnt(entvars_t *pev) { return (pev == NULL || FNullEnt(OFFSET(pev))); } +inline BOOL FNullEnt(const edict_t *pent) { return (pent == NULL || FNullEnt(OFFSET(pent))); } +inline BOOL FStringNull(int iString) { return (iString == iStringNull); } +inline BOOL FStrEq(const char *sz1, const char *sz2) { return (strcmp(sz1, sz2) == 0); } +inline BOOL FClassnameIs(entvars_t *pev, const char *szClassname) { return FStrEq(STRING(pev->classname), szClassname); } +inline BOOL FClassnameIs(edict_t *pent, const char *szClassname) { return FStrEq(STRING(VARS(pent)->classname), szClassname); } + +inline void UTIL_MakeVectorsPrivate(Vector vecAngles, float *p_vForward, float *p_vRight, float *p_vUp) { g_engfuncs.pfnAngleVectors(vecAngles, p_vForward, p_vRight, p_vUp); } + +// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 +// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 +// down to 1 is a lower pitch. 150 to 70 is the realistic range. +// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as +// fast as EMIT_SOUND (the pitchshift mixer is not native coded). +inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) +{ + EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); +} + +inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) +{ + EMIT_SOUND_DYN2(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); +} + +inline void UTIL_SetSize(entvars_t *pev, const Vector &vecMin, const Vector &vecMax) +{ + SET_SIZE(ENT(pev), vecMin, vecMax); +} + +inline void UTIL_SetOrigin(entvars_t *pev, const Vector &vecOrigin) +{ + edict_t *ent = ENT(pev); + + if (ent != NULL) + SET_ORIGIN(ent, vecOrigin); +} + +inline void UTIL_TraceLine(const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr) +{ + TRACE_LINE(vecStart, vecEnd, (igmon == ignore_monsters), pentIgnore, ptr); +} + +extern char *UTIL_VarArgs(char *format, ...); +extern void UTIL_LogPrintf(const char *fmt, ...); diff --git a/metamod/include/dlls/vector.h b/metamod/include/dlls/vector.h new file mode 100644 index 0000000..6427e1e --- /dev/null +++ b/metamod/include/dlls/vector.h @@ -0,0 +1,176 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +class Vector2D { +public: + inline Vector2D() : x(), y() {} + inline Vector2D(float X, float Y) : x(X), y(Y) {} + inline Vector2D(const Vector2D &v) { *(int*)&x = *(int*)&v.x; *(int*)&y = *(int*)&v.y; } + inline Vector2D operator+(const Vector2D &v) const { return Vector2D(x + v.x, y + v.y); } + inline Vector2D operator-(const Vector2D &v) const { return Vector2D(x - v.x, y - v.y); } + inline Vector2D operator*(float fl) const { return Vector2D(x * fl, y * fl); } + inline Vector2D operator/(float fl) const { return Vector2D(x / fl, y / fl); } + inline Vector2D operator/=(float fl) const { return Vector2D(x / fl, y / fl); } + + inline float Length() const { return sqrt(x * x + y * y); } + inline float LengthSquared() const { return (x * x + y * y); } + + operator float*() { return &x; } + operator const float*() const { return &x; } + + inline Vector2D Normalize() const + { + float flLen = Length(); + if (flLen == 0) + return Vector2D(0, 0); + + flLen = 1 / flLen; + return Vector2D(x * flLen, y * flLen); + } + + inline bool IsLengthLessThan(float length) const { return (LengthSquared() < length * length); } + inline bool IsLengthGreaterThan(float length) const { return (LengthSquared() > length * length); } + inline float NormalizeInPlace() + { + float flLen = Length(); + if (flLen == 0) + { + x = 1; y = 0; + } + else + { + flLen = 1 / flLen; + x *= flLen; y *= flLen; + } + + return flLen; + } + inline bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance); + } + + // Members + vec_t x, y; +}; + +inline float DotProduct(const Vector2D &a, const Vector2D &b) { return (a.x * b.x + a.y * b.y); } +inline Vector2D operator*(float fl, const Vector2D &v) { return v * fl; } + +// 3D Vector +// same data-layout as engine's vec3_t, which is a vec_t[3] +class Vector { +public: + // Construction/destruction + inline Vector() : x(), y(), z() {} + inline Vector(float X, float Y, float Z) : x(X), y(Y), z(Z) {} + inline Vector(const Vector &v) { *(int*)&x = *(int*)&v.x; *(int*)&y = *(int*)&v.y; *(int*)&z = *(int*)&v.z; } + inline Vector(const float rgfl[3]) { *(int*)&x = *(int*)&rgfl[0]; *(int*)&y = *(int*)&rgfl[1]; *(int*)&z = *(int*)&rgfl[2]; } + + // Operators + inline Vector operator-() const { return Vector(-x, -y, -z); } + inline int operator==(const Vector &v) const { return x == v.x && y == v.y && z == v.z; } + inline int operator!=(const Vector &v) const { return !(*this == v); } + inline Vector operator+(const Vector &v) const { return Vector(x + v.x, y + v.y, z + v.z); } + inline Vector operator-(const Vector &v) const { return Vector(x - v.x, y - v.y, z - v.z); } + inline Vector operator*(float fl) const { return Vector(x * fl, y * fl, z * fl); } + inline Vector operator/(float fl) const { return Vector(x / fl, y / fl, z / fl); } + inline Vector operator/=(float fl) const{ return Vector(x / fl, y / fl, z / fl); } + + // Methods + inline void CopyToArray(float *rgfl) const { *(int*)&rgfl[0] = *(int*)&x; *(int*)&rgfl[1] = *(int*)&y; *(int*)&rgfl[2] = *(int*)&z; } + inline float Length() const { return sqrt(x * x + y * y + z * z); } + inline float LengthSquared() const { return (x * x + y * y + z * z); } + + operator float*() { return &x; } // Vectors will now automatically convert to float * when needed + operator const float*() const { return &x; } // Vectors will now automatically convert to float * when needed + + inline Vector Normalize() + { + float flLen = Length(); + if (flLen == 0) + return Vector(0, 0, 1); + + flLen = 1 / flLen; + return Vector(x * flLen, y * flLen, z * flLen); + } + inline Vector2D Make2D() const + { + Vector2D Vec2; + *(int*)&Vec2.x = *(int*)&x; + *(int*)&Vec2.y = *(int*)&y; + return Vec2; + } + + inline float Length2D() const { return sqrt(x * x + y * y); } + + inline bool IsLengthLessThan(float length) const { return (LengthSquared() < length * length); } + inline bool IsLengthGreaterThan(float length) const { return (LengthSquared() > length * length); } + + inline float NormalizeInPlace() + { + float flLen = Length(); + if (flLen == 0) + { + x = 0; y = 0; z = 1; + } + else + { + flLen = 1 / flLen; + x *= flLen; y *= flLen; z *= flLen; + } + + return flLen; + } + inline bool IsZero(float tolerance = 0.01f) const + { + return (x > -tolerance && x < tolerance && + y > -tolerance && y < tolerance && + z > -tolerance && z < tolerance); + } + + // Members + vec_t x, y, z; +}; + +inline Vector operator*(float fl, const Vector &v) { return v * fl; } +inline float DotProduct(const Vector &a, const Vector &b) { return (a.x * b.x + a.y * b.y + a.z * b.z); } +inline float DotProduct2D(const Vector &a, const Vector &b) { return (a.x * b.x + a.y * b.y); } +inline Vector CrossProduct(const Vector &a, const Vector &b) { return Vector(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } + +template +inline void SWAP(T &first, T &second) +{ + T temp = first; + first = second; + second = temp; +} diff --git a/metamod/include/dlls/vehicle.h b/metamod/include/dlls/vehicle.h new file mode 100644 index 0000000..8b7a0d0 --- /dev/null +++ b/metamod/include/dlls/vehicle.h @@ -0,0 +1,53 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define VEHICLE_SPEED0_ACCELERATION 0.005000000000000000 +#define VEHICLE_SPEED1_ACCELERATION 0.002142857142857143 +#define VEHICLE_SPEED2_ACCELERATION 0.003333333333333334 +#define VEHICLE_SPEED3_ACCELERATION 0.004166666666666667 +#define VEHICLE_SPEED4_ACCELERATION 0.004000000000000000 +#define VEHICLE_SPEED5_ACCELERATION 0.003800000000000000 +#define VEHICLE_SPEED6_ACCELERATION 0.004500000000000000 +#define VEHICLE_SPEED7_ACCELERATION 0.004250000000000000 +#define VEHICLE_SPEED8_ACCELERATION 0.002666666666666667 +#define VEHICLE_SPEED9_ACCELERATION 0.002285714285714286 +#define VEHICLE_SPEED10_ACCELERATION 0.001875000000000000 +#define VEHICLE_SPEED11_ACCELERATION 0.001444444444444444 +#define VEHICLE_SPEED12_ACCELERATION 0.001200000000000000 +#define VEHICLE_SPEED13_ACCELERATION 0.000916666666666666 + +#define VEHICLE_STARTPITCH 60 +#define VEHICLE_MAXPITCH 200 +#define VEHICLE_MAXSPEED 1500 + +class CFuncVehicleControls: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual int ObjectCaps() = 0; +}; diff --git a/metamod/include/dlls/weapons.h b/metamod/include/dlls/weapons.h new file mode 100644 index 0000000..e17cc27 --- /dev/null +++ b/metamod/include/dlls/weapons.h @@ -0,0 +1,894 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "weapontype.h" + +class CBasePlayer; + +#define MAX_WEAPONS 32 +#define MAX_NORMAL_BATTERY 100.0f +#define DISTANCE_RELOAD_SOUND 512.0f + +#define ITEM_FLAG_SELECTONEMPTY 1 +#define ITEM_FLAG_NOAUTORELOAD 2 +#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 +#define ITEM_FLAG_LIMITINWORLD 8 +#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon + +#define WEAPON_IS_ONTARGET 0x40 + +// the maximum amount of ammo each weapon's clip can hold +#define WEAPON_NOCLIP -1 + +#define LOUD_GUN_VOLUME 1000 +#define NORMAL_GUN_VOLUME 600 +#define QUIET_GUN_VOLUME 200 + +#define BRIGHT_GUN_FLASH 512 +#define NORMAL_GUN_FLASH 256 +#define DIM_GUN_FLASH 128 + +#define BIG_EXPLOSION_VOLUME 2048 +#define NORMAL_EXPLOSION_VOLUME 1024 +#define SMALL_EXPLOSION_VOLUME 512 + +#define WEAPON_ACTIVITY_VOLUME 64 + +// spawn flags +#define SF_DETONATE 0x0001 // Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges + +// custom enum +enum ArmorType +{ + ARMOR_NONE, // no armor + ARMOR_KEVLAR, // body vest only + ARMOR_VESTHELM, // vest and helmet +}; + +enum ArmouryItemPack +{ + ARMOURY_MP5NAVY, + ARMOURY_TMP, + ARMOURY_P90, + ARMOURY_MAC10, + ARMOURY_AK47, + ARMOURY_SG552, + ARMOURY_M4A1, + ARMOURY_AUG, + ARMOURY_SCOUT, + ARMOURY_G3SG1, + ARMOURY_AWP, + ARMOURY_M3, + ARMOURY_XM1014, + ARMOURY_M249, + ARMOURY_FLASHBANG, + ARMOURY_HEGRENADE, + ARMOURY_KEVLAR, + ARMOURY_ASSAULT, + ARMOURY_SMOKEGRENADE +}; + +struct ItemInfo +{ + int iSlot; + int iPosition; + const char *pszAmmo1; + int iMaxAmmo1; + const char *pszAmmo2; + int iMaxAmmo2; + const char *pszName; + int iMaxClip; + int iId; + int iFlags; + int iWeight; +}; + +struct AmmoInfo +{ + const char *pszName; + int iId; +}; + +struct MULTIDAMAGE +{ + CBaseEntity *pEntity; + float amount; + int type; +}; + +class CArmoury: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void Restart() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; +public: + ArmouryItemPack m_iItem; + int m_iCount; + int m_iInitialCount; + bool m_bAlreadyCounted; +}; + +// Smoke Grenade / HE grenade / Flashbang grenade / C4 +class CGrenade: public CBaseMonster { +public: + virtual void Spawn() = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual int ObjectCaps() = 0; + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual int BloodColor() = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual void BounceSound() = 0; +public: + bool m_bStartDefuse; + bool m_bIsC4; + EHANDLE m_pBombDefuser; + float m_flDefuseCountDown; + float m_flC4Blow; + float m_flNextFreqInterval; + float m_flNextBeep; + float m_flNextFreq; + char *m_sBeepName; + float m_fAttenu; + float m_flNextBlink; + float m_fNextDefuse; + bool m_bJustBlew; + int m_iTeam; + int m_iCurWave; + edict_t *m_pentCurBombTarget; + int m_SGSmoke; + int m_angle; + unsigned short m_usEvent; + bool m_bLightSmoke; + bool m_bDetonated; + Vector m_vSmokeDetonate; + int m_iBounceCount; + BOOL m_fRegisteredSound; // whether or not this grenade has issued its DANGER sound to the world sound list yet. +}; + +// Items that the player has in their inventory that they can use +class CBasePlayerItem: public CBaseAnimating { +public: + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void SetObjectCollisionBox() = 0; + virtual CBaseEntity *Respawn() = 0; + virtual int AddToPlayer(CBasePlayer *pPlayer) = 0; // return TRUE if the item you want the item added to the player inventory + virtual int AddDuplicate(CBasePlayerItem *pItem) = 0; // return TRUE if you want your duplicate removed from world + virtual int GetItemInfo(ItemInfo *p) = 0; // returns 0 if struct not filled out + virtual BOOL CanDeploy() = 0; + virtual BOOL CanDrop() = 0; // returns is deploy was successful + virtual BOOL Deploy() = 0; + virtual BOOL IsWeapon() = 0; + virtual BOOL CanHolster() = 0; // can this weapon be put away right now? + virtual void Holster(int skiplocal = 0) = 0; + virtual void UpdateItemInfo() = 0; + virtual void ItemPreFrame() = 0; // called each frame by the player PreThink + virtual void ItemPostFrame() = 0; // called each frame by the player PostThink + virtual void Drop() = 0; + virtual void Kill() = 0; + virtual void AttachToPlayer(CBasePlayer *pPlayer) = 0; + virtual int PrimaryAmmoIndex() = 0; + virtual int SecondaryAmmoIndex() = 0; + virtual int UpdateClientData(CBasePlayer *pPlayer) = 0; + virtual CBasePlayerItem *GetWeaponPtr() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; // return 0 to MAX_ITEMS_SLOTS, used in hud +public: + CBasePlayer *m_pPlayer; + CBasePlayerItem *m_pNext; + int m_iId; // WEAPON_??? +}; + +// inventory items that +class CBasePlayerWeapon: public CBasePlayerItem { +public: + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + + // generic weapon versions of CBasePlayerItem calls + virtual int AddToPlayer(CBasePlayer *pPlayer) = 0; + virtual int AddDuplicate(CBasePlayerItem *pItem) = 0; + virtual BOOL CanDeploy() = 0; + virtual BOOL IsWeapon() = 0; + virtual void Holster(int skiplocal = 0) = 0; + virtual void UpdateItemInfo() = 0; + virtual void ItemPostFrame() = 0; + virtual int PrimaryAmmoIndex() = 0; + virtual int SecondaryAmmoIndex() = 0; + virtual int UpdateClientData(CBasePlayer *pPlayer) = 0; + virtual CBasePlayerItem *GetWeaponPtr() = 0; + virtual int ExtractAmmo(CBasePlayerWeapon *pWeapon) = 0; + virtual int ExtractClipAmmo(CBasePlayerWeapon *pWeapon) = 0; + virtual int AddWeapon() = 0; + virtual BOOL PlayEmptySound() = 0; + virtual void ResetEmptySound() = 0; + virtual void SendWeaponAnim(int iAnim, int skiplocal = 0) = 0; + virtual BOOL IsUseable() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual void RetireWeapon() = 0; + virtual BOOL ShouldWeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + BOOL IsPistol() { return (m_iId == WEAPON_USP || m_iId == WEAPON_GLOCK18 || m_iId == WEAPON_P228 || m_iId == WEAPON_DEAGLE || m_iId == WEAPON_ELITE || m_iId == WEAPON_FIVESEVEN); } + + int m_iPlayEmptySound; + int m_fFireOnEmpty; + float m_flNextPrimaryAttack; // soonest time ItemPostFrame will call PrimaryAttack + float m_flNextSecondaryAttack; // soonest time ItemPostFrame will call SecondaryAttack + float m_flTimeWeaponIdle; // soonest time ItemPostFrame will call WeaponIdle + int m_iPrimaryAmmoType; // "primary" ammo index into players m_rgAmmo[] + int m_iSecondaryAmmoType; // "secondary" ammo index into players m_rgAmmo[] + int m_iClip; // number of shots left in the primary weapon clip, -1 it not used + int m_iClientClip; // the last version of m_iClip sent to hud dll + int m_iClientWeaponState; // the last version of the weapon state sent to hud dll (is current weapon, is on target) + int m_fInReload; // Are we in the middle of a reload; + int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns + int m_iDefaultAmmo; // how much ammo you get when you pick up this weapon as placed by a level designer. + int m_iShellId; + float m_fMaxSpeed; + bool m_bDelayFire; + int m_iDirection; + bool m_bSecondarySilencerOn; + float m_flAccuracy; + float m_flLastFire; + int m_iShotsFired; + Vector m_vVecAiming; + string_t model_name; + float m_flGlock18Shoot; // time to shoot the remaining bullets of the glock18 burst fire + int m_iGlock18ShotsFired; // used to keep track of the shots fired during the Glock18 burst fire mode. + float m_flFamasShoot; + int m_iFamasShotsFired; + float m_fBurstSpread; + int m_iWeaponState; + float m_flNextReload; + float m_flDecreaseShotsFired; + unsigned short m_usFireGlock18; + unsigned short m_usFireFamas; + + // hle time creep vars + float m_flPrevPrimaryAttack; + float m_flLastFireTime; +}; + +class CBasePlayerAmmo: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual BOOL AddAmmo(CBaseEntity *pOther) = 0; + virtual CBaseEntity *Respawn() = 0; +}; + +class CWeaponBox: public CBaseEntity { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual int Save(CSave &save) = 0; + virtual int Restore(CRestore &restore) = 0; + virtual void SetObjectCollisionBox() = 0; + virtual void Touch(CBaseEntity *pOther) = 0; +public: + CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; + int m_rgiszAmmo[MAX_AMMO_SLOTS]; + int m_rgAmmo[MAX_AMMO_SLOTS]; + int m_cAmmoTypes; + bool m_bIsBomb; +}; + +class CUSP: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; + +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireUSP; } +private: + unsigned short m_usFireUSP; +}; + +class CMP5N: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireMP5N; } +private: + unsigned short m_usFireMP5N; +}; + +class CSG552: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireSG552; } +private: + unsigned short m_usFireSG552; +}; + +class CAK47: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireAK47; } +private: + unsigned short m_usFireAK47; +}; + +class CAUG: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireAug; } +private: + unsigned short m_usFireAug; +}; + +class CAWP: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireAWP; } +private: + unsigned short m_usFireAWP; +}; + +class CC4: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual void KeyValue(KeyValueData *pkvd) = 0; + virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal) = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + bool m_bStartedArming; + bool m_bBombPlacedAnimation; + float m_fArmedTime; + bool HasShield() const { return m_bHasShield; } +private: + bool m_bHasShield; +}; + +class CDEAGLE: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireDeagle; } +private: + unsigned short m_usFireDeagle; +}; + +class CFlashbang: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL CanDeploy() = 0; + virtual BOOL CanDrop() = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal) = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +}; + +class CG3SG1: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireG3SG1; } +private: + unsigned short m_usFireG3SG1; +}; + +class CGLOCK18: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +public: + int m_iShell; + bool m_bBurstFire; +}; + +class CHEGrenade: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL CanDeploy() = 0; + virtual BOOL CanDrop() = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal) = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + unsigned short m_usCreateExplosion; +}; + +class CKnife: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL CanDrop() = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal) = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual BOOL UseDecrement() = 0; + virtual void WeaponIdle() = 0; +public: + TraceResult m_trHit; + unsigned short m_usKnife; +}; + +class CM249: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireM249; } +private: + unsigned short m_usFireM249; +}; + +class CM3: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + float m_flPumpTime; + unsigned short GetEventID() const { return m_usFireM3; } +private: + unsigned short m_usFireM3; +}; + +class CM4A1: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireM4A1; } +private: + unsigned short m_usFireM4A1; +}; + +class CMAC10: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireMAC10; } +private: + unsigned short m_usFireMAC10; +}; + +class CP228: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireP228; } +private: + unsigned short m_usFireP228; +}; + +class CP90: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireP90; } +private: + unsigned short m_usFireP90; +}; + +class CSCOUT: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireScout; } +private: + unsigned short m_usFireScout; +}; + +class CSmokeGrenade: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL CanDeploy() = 0; + virtual BOOL CanDrop() = 0; + virtual BOOL Deploy() = 0; + virtual void Holster(int skiplocal) = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + unsigned short m_usCreateSmoke; +}; + +class CTMP: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireTMP; } +private: + unsigned short m_usFireTMP; +}; + +class CXM1014: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + float m_flPumpTime; + unsigned short GetEventID() const { return m_usFireXM1014; } +private: + unsigned short m_usFireXM1014; +}; + +class CELITE: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +public: + int m_iShell; + unsigned short GetEventID_Left() const { return m_usFireELITE_LEFT; } + unsigned short GetEventID_Right() const { return m_usFireELITE_RIGHT; } +private: + unsigned short m_usFireELITE_LEFT; + unsigned short m_usFireELITE_RIGHT; +}; + +class CFiveSeven: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; + virtual BOOL IsPistol() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireFiveSeven; } +private: + unsigned short m_usFireFiveSeven; +}; + +class CUMP45: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireUMP45; } +private: + unsigned short m_usFireUMP45; +}; + +class CSG550: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + unsigned short GetEventID() const { return m_usFireSG550; } +private: + unsigned short m_usFireSG550; +}; + +class CGalil: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; + unsigned short GetEventID() const { return m_usFireGalil; } +private: + unsigned short m_usFireGalil; +}; + +class CFamas: public CBasePlayerWeapon { +public: + virtual void Spawn() = 0; + virtual void Precache() = 0; + virtual int GetItemInfo(ItemInfo *p) = 0; + virtual BOOL Deploy() = 0; + virtual float GetMaxSpeed() = 0; + virtual int iItemSlot() = 0; + virtual void PrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + virtual void WeaponIdle() = 0; + virtual BOOL UseDecrement() = 0; +public: + int m_iShell; + int iShellOn; +}; diff --git a/metamod/include/dlls/weapontype.h b/metamod/include/dlls/weapontype.h new file mode 100644 index 0000000..10e5b67 --- /dev/null +++ b/metamod/include/dlls/weapontype.h @@ -0,0 +1,412 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +enum WeaponIdType +{ + WEAPON_NONE, + WEAPON_P228, + WEAPON_GLOCK, + WEAPON_SCOUT, + WEAPON_HEGRENADE, + WEAPON_XM1014, + WEAPON_C4, + WEAPON_MAC10, + WEAPON_AUG, + WEAPON_SMOKEGRENADE, + WEAPON_ELITE, + WEAPON_FIVESEVEN, + WEAPON_UMP45, + WEAPON_SG550, + WEAPON_GALIL, + WEAPON_FAMAS, + WEAPON_USP, + WEAPON_GLOCK18, + WEAPON_AWP, + WEAPON_MP5N, + WEAPON_M249, + WEAPON_M3, + WEAPON_M4A1, + WEAPON_TMP, + WEAPON_G3SG1, + WEAPON_FLASHBANG, + WEAPON_DEAGLE, + WEAPON_SG552, + WEAPON_AK47, + WEAPON_KNIFE, + WEAPON_P90, + WEAPON_SHIELDGUN = 99 +}; + +enum AutoBuyClassType +{ + AUTOBUYCLASS_NONE = 0, + AUTOBUYCLASS_PRIMARY = (1 << 0), + AUTOBUYCLASS_SECONDARY = (1 << 1), + AUTOBUYCLASS_AMMO = (1 << 2), + AUTOBUYCLASS_ARMOR = (1 << 3), + AUTOBUYCLASS_DEFUSER = (1 << 4), + AUTOBUYCLASS_PISTOL = (1 << 5), + AUTOBUYCLASS_SMG = (1 << 6), + AUTOBUYCLASS_RIFLE = (1 << 7), + AUTOBUYCLASS_SNIPERRIFLE = (1 << 8), + AUTOBUYCLASS_SHOTGUN = (1 << 9), + AUTOBUYCLASS_MACHINEGUN = (1 << 10), + AUTOBUYCLASS_GRENADE = (1 << 11), + AUTOBUYCLASS_NIGHTVISION = (1 << 12), + AUTOBUYCLASS_SHIELD = (1 << 13), +}; + +enum AmmoCostType +{ + AMMO_338MAG_PRICE = 125, + AMMO_357SIG_PRICE = 50, + AMMO_45ACP_PRICE = 25, + AMMO_50AE_PRICE = 40, + AMMO_556MM_PRICE = 60, + AMMO_57MM_PRICE = 50, + AMMO_762MM_PRICE = 80, + AMMO_9MM_PRICE = 20, + AMMO_BUCKSHOT_PRICE = 65, +}; + +enum WeaponCostType +{ + AK47_PRICE = 2500, + AWP_PRICE = 4750, + DEAGLE_PRICE = 650, + G3SG1_PRICE = 5000, + SG550_PRICE = 4200, + GLOCK18_PRICE = 400, + M249_PRICE = 5750, + M3_PRICE = 1700, + M4A1_PRICE = 3100, + AUG_PRICE = 3500, + MP5NAVY_PRICE = 1500, + P228_PRICE = 600, + P90_PRICE = 2350, + UMP45_PRICE = 1700, + MAC10_PRICE = 1400, + SCOUT_PRICE = 2750, + SG552_PRICE = 3500, + TMP_PRICE = 1250, + USP_PRICE = 500, + ELITE_PRICE = 800, + FIVESEVEN_PRICE = 750, + XM1014_PRICE = 3000, + GALIL_PRICE = 2000, + FAMAS_PRICE = 2250, + SHIELDGUN_PRICE = 2200, +}; + +enum WeaponState +{ + WPNSTATE_USP_SILENCED = (1 << 0), + WPNSTATE_GLOCK18_BURST_MODE = (1 << 1), + WPNSTATE_M4A1_SILENCED = (1 << 2), + WPNSTATE_ELITE_LEFT = (1 << 3), + WPNSTATE_FAMAS_BURST_MODE = (1 << 4), + WPNSTATE_SHIELD_DRAWN = (1 << 5), +}; + +// custom enum +// the default amount of ammo that comes with each gun when it spawns +enum ClipGiveDefault +{ + P228_DEFAULT_GIVE = 13, + GLOCK18_DEFAULT_GIVE = 20, + SCOUT_DEFAULT_GIVE = 10, + HEGRENADE_DEFAULT_GIVE = 1, + XM1014_DEFAULT_GIVE = 7, + C4_DEFAULT_GIVE = 1, + MAC10_DEFAULT_GIVE = 30, + AUG_DEFAULT_GIVE = 30, + SMOKEGRENADE_DEFAULT_GIVE = 1, + ELITE_DEFAULT_GIVE = 30, + FIVESEVEN_DEFAULT_GIVE = 20, + UMP45_DEFAULT_GIVE = 25, + SG550_DEFAULT_GIVE = 30, + GALIL_DEFAULT_GIVE = 35, + FAMAS_DEFAULT_GIVE = 25, + USP_DEFAULT_GIVE = 12, + AWP_DEFAULT_GIVE = 10, + MP5NAVY_DEFAULT_GIVE = 30, + M249_DEFAULT_GIVE = 100, + M3_DEFAULT_GIVE = 8, + M4A1_DEFAULT_GIVE = 30, + TMP_DEFAULT_GIVE = 30, + G3SG1_DEFAULT_GIVE = 20, + FLASHBANG_DEFAULT_GIVE = 1, + DEAGLE_DEFAULT_GIVE = 7, + SG552_DEFAULT_GIVE = 30, + AK47_DEFAULT_GIVE = 30, + /*KNIFE_DEFAULT_GIVE = 1,*/ + P90_DEFAULT_GIVE = 50, +}; + +enum ClipSizeType +{ + P228_MAX_CLIP = 13, + GLOCK18_MAX_CLIP = 20, + SCOUT_MAX_CLIP = 10, + XM1014_MAX_CLIP = 7, + MAC10_MAX_CLIP = 30, + AUG_MAX_CLIP = 30, + ELITE_MAX_CLIP = 30, + FIVESEVEN_MAX_CLIP = 20, + UMP45_MAX_CLIP = 25, + SG550_MAX_CLIP = 30, + GALIL_MAX_CLIP = 35, + FAMAS_MAX_CLIP = 25, + USP_MAX_CLIP = 12, + AWP_MAX_CLIP = 10, + MP5N_MAX_CLIP = 30, + M249_MAX_CLIP = 100, + M3_MAX_CLIP = 8, + M4A1_MAX_CLIP = 30, + TMP_MAX_CLIP = 30, + G3SG1_MAX_CLIP = 20, + DEAGLE_MAX_CLIP = 7, + SG552_MAX_CLIP = 30, + AK47_MAX_CLIP = 30, + P90_MAX_CLIP = 50, +}; + +enum WeightWeapon +{ + P228_WEIGHT = 5, + GLOCK18_WEIGHT = 5, + SCOUT_WEIGHT = 30, + HEGRENADE_WEIGHT = 2, + XM1014_WEIGHT = 20, + C4_WEIGHT = 3, + MAC10_WEIGHT = 25, + AUG_WEIGHT = 25, + SMOKEGRENADE_WEIGHT = 1, + ELITE_WEIGHT = 5, + FIVESEVEN_WEIGHT = 5, + UMP45_WEIGHT = 25, + SG550_WEIGHT = 20, + GALIL_WEIGHT = 25, + FAMAS_WEIGHT = 75, + USP_WEIGHT = 5, + AWP_WEIGHT = 30, + MP5NAVY_WEIGHT = 25, + M249_WEIGHT = 25, + M3_WEIGHT = 20, + M4A1_WEIGHT = 25, + TMP_WEIGHT = 25, + G3SG1_WEIGHT = 20, + FLASHBANG_WEIGHT = 1, + DEAGLE_WEIGHT = 7, + SG552_WEIGHT = 25, + AK47_WEIGHT = 25, + P90_WEIGHT = 26, + KNIFE_WEIGHT = 0, +}; + +enum MaxAmmoType +{ + MAX_AMMO_BUCKSHOT = 32, + MAX_AMMO_9MM = 120, + MAX_AMMO_556NATO = 90, + MAX_AMMO_556NATOBOX = 200, + MAX_AMMO_762NATO = 90, + MAX_AMMO_45ACP = 100, + MAX_AMMO_50AE = 35, + MAX_AMMO_338MAGNUM = 30, + MAX_AMMO_57MM = 100, + MAX_AMMO_357SIG = 52, + + // custom + MAX_AMMO_SMOKEGRENADE = 1, + MAX_AMMO_HEGRENADE = 1, + MAX_AMMO_FLASHBANG = 2, +}; + +enum AmmoType +{ + AMMO_NONE = -1, + AMMO_BUCKSHOT, + AMMO_9MM, + AMMO_556NATO, + AMMO_556NATOBOX, + AMMO_762NATO, + AMMO_45ACP, + AMMO_50AE, + AMMO_338MAGNUM, + AMMO_57MM, + AMMO_357SIG, + AMMO_MAX_TYPES, +}; + +enum WeaponClassType +{ + WEAPONCLASS_NONE, + WEAPONCLASS_KNIFE, + WEAPONCLASS_PISTOL, + WEAPONCLASS_GRENADE, + WEAPONCLASS_SUBMACHINEGUN, + WEAPONCLASS_SHOTGUN, + WEAPONCLASS_MACHINEGUN, + WEAPONCLASS_RIFLE, + WEAPONCLASS_SNIPERRIFLE, + WEAPONCLASS_MAX, +}; + +enum AmmoBuyAmount +{ + AMMO_338MAG_BUY = 10, + AMMO_357SIG_BUY = 13, + AMMO_45ACP_BUY = 12, + AMMO_50AE_BUY = 7, + AMMO_556NATO_BUY = 30, + AMMO_556NATOBOX_BUY = 30, + AMMO_57MM_BUY = 50, + AMMO_762NATO_BUY = 30, + AMMO_9MM_BUY = 30, + AMMO_BUCKSHOT_BUY = 8, +}; + +enum ItemCostType +{ + ASSAULTSUIT_PRICE = 1000, + FLASHBANG_PRICE = 200, + HEGRENADE_PRICE = 300, + SMOKEGRENADE_PRICE = 300, + KEVLAR_PRICE = 650, + HELMET_PRICE = 350, + NVG_PRICE = 1250, + DEFUSEKIT_PRICE = 200, +}; + +enum shieldgun_e +{ + SHIELDGUN_IDLE, + SHIELDGUN_SHOOT1, + SHIELDGUN_SHOOT2, + SHIELDGUN_SHOOT_EMPTY, + SHIELDGUN_RELOAD, + SHIELDGUN_DRAW, + SHIELDGUN_DRAWN_IDLE, + SHIELDGUN_UP, + SHIELDGUN_DOWN, +}; + +// custom +enum shieldgren_e +{ + SHIELDREN_IDLE = 4, + SHIELDREN_UP, + SHIELDREN_DOWN +}; + +enum InventorySlotType +{ + NONE_SLOT, + PRIMARY_WEAPON_SLOT, + PISTOL_SLOT, + KNIFE_SLOT, + GRENADE_SLOT, + C4_SLOT, +}; + +enum Bullet +{ + BULLET_NONE, + BULLET_PLAYER_9MM, + BULLET_PLAYER_MP5, + BULLET_PLAYER_357, + BULLET_PLAYER_BUCKSHOT, + BULLET_PLAYER_CROWBAR, + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, + BULLET_PLAYER_45ACP, + BULLET_PLAYER_338MAG, + BULLET_PLAYER_762MM, + BULLET_PLAYER_556MM, + BULLET_PLAYER_50AE, + BULLET_PLAYER_57MM, + BULLET_PLAYER_357SIG, +}; + +struct WeaponStruct +{ + int m_type; + int m_price; + int m_side; + int m_slot; + int m_ammoPrice; +}; + +struct AutoBuyInfoStruct +{ + AutoBuyClassType m_class; + char *m_command; + char *m_classname; +}; + +struct WeaponAliasInfo +{ + char *alias; + WeaponIdType id; +}; + +struct WeaponBuyAliasInfo +{ + char *alias; + WeaponIdType id; + char *failName; +}; + +struct WeaponClassAliasInfo +{ + char *alias; + WeaponClassType id; +}; + +struct WeaponInfoStruct +{ + int id; + int cost; + int clipCost; + int buyClipSize; + int gunClipSize; + int maxRounds; + int ammoType; + char *entityName; + const char *ammoName; +}; + +struct WeaponSlotInfo +{ + WeaponIdType id; + InventorySlotType slot; + const char *weaponName; +}; diff --git a/metamod/include/dlls/wpn_shared.h b/metamod/include/dlls/wpn_shared.h new file mode 100644 index 0000000..1ed2eea --- /dev/null +++ b/metamod/include/dlls/wpn_shared.h @@ -0,0 +1,598 @@ +#pragma once + +//AK47 +#define AK47_MAX_SPEED 221 +#define AK47_DAMAGE 36 +#define AK47_RANGE_MODIFER 0.98 +#define AK47_RELOAD_TIME 2.45 + +enum ak47_e +{ + AK47_IDLE1, + AK47_RELOAD, + AK47_DRAW, + AK47_SHOOT1, + AK47_SHOOT2, + AK47_SHOOT3 +}; + + + +//AUG +#define AUG_MAX_SPEED 240 +#define AUG_DAMAGE 32 +#define AUG_RANGE_MODIFER 0.96 +#define AUG_RELOAD_TIME 3.3 + +enum aug_e +{ + AUG_IDLE1, + AUG_RELOAD, + AUG_DRAW, + AUG_SHOOT1, + AUG_SHOOT2, + AUG_SHOOT3 +}; + + + +//AWP +#define AWP_MAX_SPEED 210 +#define AWP_MAX_SPEED_ZOOM 150 +#define AWP_DAMAGE 115 +#define AWP_RANGE_MODIFER 0.99 +#define AWP_RELOAD_TIME 2.5 + +enum awp_e +{ + AWP_IDLE, + AWP_SHOOT, + AWP_SHOOT2, + AWP_SHOOT3, + AWP_RELOAD, + AWP_DRAW, +}; + + + +//C4 +#define C4_MAX_AMMO 1 +#define C4_MAX_SPEED 250.0 +#define C4_ARMING_ON_TIME 3.0 + +enum c4_e +{ + C4_IDLE1, + C4_DRAW, + C4_DROP, + C4_ARM +}; + + + +//Deagle +#define DEAGLE_MAX_SPEED 250 +#define DEAGLE_DAMAGE 54 +#define DEAGLE_RANGE_MODIFER 0.81 +#define DEAGLE_RELOAD_TIME 2.2 + +enum deagle_e +{ + DEAGLE_IDLE1, + DEAGLE_SHOOT1, + DEAGLE_SHOOT2, + DEAGLE_SHOOT_EMPTY, + DEAGLE_RELOAD, + DEAGLE_DRAW +}; + + + +//Elites +#define ELITE_MAX_SPEED 250 +#define ELITE_RELOAD_TIME 4.5 +#define ELITE_DAMAGE 36 +#define ELITE_RANGE_MODIFER 0.75 + +enum elite_e +{ + ELITE_IDLE, + ELITE_IDLE_LEFTEMPTY, + ELITE_SHOOTLEFT1, + ELITE_SHOOTLEFT2, + ELITE_SHOOTLEFT3, + ELITE_SHOOTLEFT4, + ELITE_SHOOTLEFT5, + ELITE_SHOOTLEFTLAST, + ELITE_SHOOTRIGHT1, + ELITE_SHOOTRIGHT2, + ELITE_SHOOTRIGHT3, + ELITE_SHOOTRIGHT4, + ELITE_SHOOTRIGHT5, + ELITE_SHOOTRIGHTLAST, + ELITE_RELOAD, + ELITE_DRAW +}; + + + +//Famas +#define FAMAS_MAX_SPEED 240 +#define FAMAS_RELOAD_TIME 3.3 +#define FAMAS_DAMAGE 30 +#define FAMAS_DAMAGE_BURST 34 +#define FAMAS_RANGE_MODIFER 0.96 + +enum famas_e +{ + FAMAS_IDLE1, + FAMAS_RELOAD, + FAMAS_DRAW, + FAMAS_SHOOT1, + FAMAS_SHOOT2, + FAMAS_SHOOT3 +}; + + + +//Fiveseven +#define FIVESEVEN_MAX_SPEED 250 +#define FIVESEVEN_DAMAGE 20 +#define FIVESEVEN_RANGE_MODIFER 0.885 +#define FIVESEVEN_RELOAD_TIME 2.7 + +enum fiveseven_e +{ + FIVESEVEN_IDLE, + FIVESEVEN_SHOOT1, + FIVESEVEN_SHOOT2, + FIVESEVEN_SHOOT_EMPTY, + FIVESEVEN_RELOAD, + FIVESEVEN_DRAW +}; + + + +//Flashbang +#define FLASHBANG_MAX_SPEED 250 +#define FLASHBANG_MAX_SPEED_SHIELD 180 + +enum flashbang_e +{ + FLASHBANG_IDLE, + FLASHBANG_PULLPIN, + FLASHBANG_THROW, + FLASHBANG_DRAW +}; + + + +//g3sg1 +#define G3SG1_MAX_SPEED 210 +#define G3SG1_MAX_SPEED_ZOOM 150 +#define G3SG1_DAMAGE 80 +#define G3SG1_RANGE_MODIFER 0.98 +#define G3SG1_RELOAD_TIME 3.5 + +enum g3sg1_e +{ + G3SG1_IDLE, + G3SG1_SHOOT, + G3SG1_SHOOT2, + G3SG1_RELOAD, + G3SG1_DRAW +}; + + + +//galil +#define GALIL_MAX_SPEED 240 +#define GALIL_DAMAGE 30 +#define GALIL_RANGE_MODIFER 0.98 +#define GALIL_RELOAD_TIME 2.45 + +enum galil_e +{ + GALIL_IDLE1, + GALIL_RELOAD, + GALIL_DRAW, + GALIL_SHOOT1, + GALIL_SHOOT2, + GALIL_SHOOT3 +}; + + + +//glock18 +#define GLOCK18_MAX_SPEED 250 +#define GLOCK18_DAMAGE 25 +#define GLOCK18_RANGE_MODIFER 0.75 +#define GLOCK18_RELOAD_TIME 2.2 + +enum glock18_e +{ + GLOCK18_IDLE1, + GLOCK18_IDLE2, + GLOCK18_IDLE3, + GLOCK18_SHOOT, + GLOCK18_SHOOT2, + GLOCK18_SHOOT3, + GLOCK18_SHOOT_EMPTY, + GLOCK18_RELOAD, + GLOCK18_DRAW, + GLOCK18_HOLSTER, + GLOCK18_ADD_SILENCER, + GLOCK18_DRAW2, + GLOCK18_RELOAD2 +}; + +enum glock18_shield_e +{ + GLOCK18_SHIELD_IDLE1, + GLOCK18_SHIELD_SHOOT, + GLOCK18_SHIELD_SHOOT2, + GLOCK18_SHIELD_SHOOT_EMPTY, + GLOCK18_SHIELD_RELOAD, + GLOCK18_SHIELD_DRAW, + GLOCK18_SHIELD_IDLE, + GLOCK18_SHIELD_UP, + GLOCK18_SHIELD_DOWN +}; + + + +//hegrenade +#define HEGRENADE_MAX_SPEED 250 +#define HEGRENADE_MAX_SPEED_SHIELD 180 + +enum hegrenade_e +{ + HEGRENADE_IDLE, + HEGRENADE_PULLPIN, + HEGRENADE_THROW, + HEGRENADE_DRAW +}; + + + +//knife +#define KNIFE_BODYHIT_VOLUME 128 +#define KNIFE_WALLHIT_VOLUME 512 +#define KNIFE_MAX_SPEED 250 +#define KNIFE_MAX_SPEED_SHIELD 180 + +enum knife_e +{ + KNIFE_IDLE, + KNIFE_ATTACK1HIT, + KNIFE_ATTACK2HIT, + KNIFE_DRAW, + KNIFE_STABHIT, + KNIFE_STABMISS, + KNIFE_MIDATTACK1HIT, + KNIFE_MIDATTACK2HIT +}; + +enum knife_shield_e +{ + KNIFE_SHIELD_IDLE, + KNIFE_SHIELD_SLASH, + KNIFE_SHIELD_ATTACKHIT, + KNIFE_SHIELD_DRAW, + KNIFE_SHIELD_UPIDLE, + KNIFE_SHIELD_UP, + KNIFE_SHIELD_DOWN +}; + + + +//m3 +#define M3_MAX_SPEED 230 +#define M3_CONE_VECTOR Vector(0.0675, 0.0675, 0.0) // special shotgun spreads + +enum m3_e +{ + M3_IDLE, + M3_FIRE1, + M3_FIRE2, + M3_RELOAD, + M3_PUMP, + M3_START_RELOAD, + M3_DRAW, + M3_HOLSTER +}; + + + +//m4a1 +#define M4A1_MAX_SPEED 230 +#define M4A1_DAMAGE 32 +#define M4A1_DAMAGE_SIL 33 +#define M4A1_RANGE_MODIFER 0.97 +#define M4A1_RANGE_MODIFER_SIL 0.95 +#define M4A1_RELOAD_TIME 3.05 + +enum m4a1_e +{ + M4A1_IDLE, + M4A1_SHOOT1, + M4A1_SHOOT2, + M4A1_SHOOT3, + M4A1_RELOAD, + M4A1_DRAW, + M4A1_ATTACH_SILENCER, + M4A1_UNSIL_IDLE, + M4A1_UNSIL_SHOOT1, + M4A1_UNSIL_SHOOT2, + M4A1_UNSIL_SHOOT3, + M4A1_UNSIL_RELOAD, + M4A1_UNSIL_DRAW, + M4A1_DETACH_SILENCER +}; + + + +//m249 +#define M249_MAX_SPEED 220 +#define M249_DAMAGE 32 +#define M249_RANGE_MODIFER 0.97 +#define M249_RELOAD_TIME 4.7 + +enum m249_e +{ + M249_IDLE1, + M249_SHOOT1, + M249_SHOOT2, + M249_RELOAD, + M249_DRAW +}; + + + +//mac10 +#define MAC10_MAX_SPEED 250 +#define MAC10_DAMAGE 29 +#define MAC10_RANGE_MODIFER 0.82 +#define MAC10_RELOAD_TIME 3.15 + +enum mac10_e +{ + MAC10_IDLE1, + MAC10_RELOAD, + MAC10_DRAW, + MAC10_SHOOT1, + MAC10_SHOOT2, + MAC10_SHOOT3 +}; + + + +//mp5navy +#define MP5N_MAX_SPEED 250 +#define MP5N_DAMAGE 26 +#define MP5N_RANGE_MODIFER 0.84 +#define MP5N_RELOAD_TIME 2.63 + +enum mp5n_e +{ + MP5N_IDLE1, + MP5N_RELOAD, + MP5N_DRAW, + MP5N_SHOOT1, + MP5N_SHOOT2, + MP5N_SHOOT3 +}; + + + +//p90 +#define P90_MAX_SPEED 245 +#define P90_DAMAGE 21 +#define P90_RANGE_MODIFER 0.885 +#define P90_RELOAD_TIME 3.4 + +enum p90_e +{ + P90_IDLE1, + P90_RELOAD, + P90_DRAW, + P90_SHOOT1, + P90_SHOOT2, + P90_SHOOT3 +}; + + + +//p228 +#define P228_MAX_SPEED 250 +#define P228_DAMAGE 32 +#define P228_RANGE_MODIFER 0.8 +#define P228_RELOAD_TIME 2.7 + +enum p228_e +{ + P228_IDLE, + P228_SHOOT1, + P228_SHOOT2, + P228_SHOOT3, + P228_SHOOT_EMPTY, + P228_RELOAD, + P228_DRAW +}; + +enum p228_shield_e +{ + P228_SHIELD_IDLE, + P228_SHIELD_SHOOT1, + P228_SHIELD_SHOOT2, + P228_SHIELD_SHOOT_EMPTY, + P228_SHIELD_RELOAD, + P228_SHIELD_DRAW, + P228_SHIELD_IDLE_UP, + P228_SHIELD_UP, + P228_SHIELD_DOWN +}; + + + +//scout +#define SCOUT_MAX_SPEED 260 +#define SCOUT_MAX_SPEED_ZOOM 220 +#define SCOUT_DAMAGE 75 +#define SCOUT_RANGE_MODIFER 0.98 +#define SCOUT_RELOAD_TIME 2 + +enum scout_e +{ + SCOUT_IDLE, + SCOUT_SHOOT, + SCOUT_SHOOT2, + SCOUT_RELOAD, + SCOUT_DRAW +}; + + + +//sg550 +#define SG550_MAX_SPEED 210 +#define SG550_MAX_SPEED_ZOOM 150 +#define SG550_DAMAGE 70 +#define SG550_RANGE_MODIFER 0.98 +#define SG550_RELOAD_TIME 3.35 + +enum sg550_e +{ + SG550_IDLE, + SG550_SHOOT, + SG550_SHOOT2, + SG550_RELOAD, + SG550_DRAW +}; + + + +//sg552 +#define SG552_MAX_SPEED 235 +#define SG552_MAX_SPEED_ZOOM 200 +#define SG552_DAMAGE 33 +#define SG552_RANGE_MODIFER 0.955 +#define SG552_RELOAD_TIME 3 + +enum sg552_e +{ + SG552_IDLE1, + SG552_RELOAD, + SG552_DRAW, + SG552_SHOOT1, + SG552_SHOOT2, + SG552_SHOOT3 +}; + + + +//smokegrenade +#define SMOKEGRENADE_MAX_SPEED 250 +#define SMOKEGRENADE_MAX_SPEED_SHIELD 180 + +enum smokegrenade_e +{ + SMOKEGRENADE_IDLE, + SMOKEGRENADE_PINPULL, + SMOKEGRENADE_THROW, + SMOKEGRENADE_DRAW +}; + + + +//tmp +#define TMP_MAX_SPEED 250 +#define TMP_DAMAGE 20 +#define TMP_RANGE_MODIFER 0.85 +#define TMP_RELOAD_TIME 2.12 + +enum tmp_e +{ + TMP_IDLE1, + TMP_RELOAD, + TMP_DRAW, + TMP_SHOOT1, + TMP_SHOOT2, + TMP_SHOOT3 +}; + + + +//ump45 +#define UMP45_MAX_SPEED 250 +#define UMP45_DAMAGE 30 +#define UMP45_RANGE_MODIFER 0.82 +#define UMP45_RELOAD_TIME 3.5 + +enum ump45_e +{ + UMP45_IDLE1, + UMP45_RELOAD, + UMP45_DRAW, + UMP45_SHOOT1, + UMP45_SHOOT2, + UMP45_SHOOT3 +}; + + + +//tmp +#define USP_MAX_SPEED 250 +#define USP_DAMAGE 34 +#define USP_DAMAGE_SIL 30 +#define USP_RANGE_MODIFER 0.79 +#define USP_RELOAD_TIME 2.7 + +enum usp_e +{ + USP_IDLE, + USP_SHOOT1, + USP_SHOOT2, + USP_SHOOT3, + USP_SHOOT_EMPTY, + USP_RELOAD, + USP_DRAW, + USP_ATTACH_SILENCER, + USP_UNSIL_IDLE, + USP_UNSIL_SHOOT1, + USP_UNSIL_SHOOT2, + USP_UNSIL_SHOOT3, + USP_UNSIL_SHOOT_EMPTY, + USP_UNSIL_RELOAD, + USP_UNSIL_DRAW, + USP_DETACH_SILENCER +}; + +enum usp_shield_e +{ + USP_SHIELD_IDLE, + USP_SHIELD_SHOOT1, + USP_SHIELD_SHOOT2, + USP_SHIELD_SHOOT_EMPTY, + USP_SHIELD_RELOAD, + USP_SHIELD_DRAW, + USP_SHIELD_UP_IDLE, + USP_SHIELD_UP, + USP_SHIELD_DOWN +}; + + + +//xm1014 +#define XM1014_MAX_SPEED 240 +#define XM1014_CONE_VECTOR Vector(0.0725, 0.0725, 0.0) // special shotgun spreads + +enum xm1014_e +{ + XM1014_IDLE, + XM1014_FIRE1, + XM1014_FIRE2, + XM1014_RELOAD, + XM1014_PUMP, + XM1014_START_RELOAD, + XM1014_DRAW +}; diff --git a/metamod/include/engine/FlightRecorder.h b/metamod/include/engine/FlightRecorder.h new file mode 100644 index 0000000..66a6477 --- /dev/null +++ b/metamod/include/engine/FlightRecorder.h @@ -0,0 +1,61 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "archtypes.h" + +class IRehldsFlightRecorder +{ +public: + virtual ~IRehldsFlightRecorder() { } + + virtual uint16 RegisterMessage(const char* module, const char *message, unsigned int version, bool inOut) = 0; + + virtual void StartMessage(uint16 msg, bool entrance) = 0; + virtual void EndMessage(uint16 msg, bool entrance) = 0; + + virtual void WriteInt8(int8 v) = 0; + virtual void WriteUInt8(uint8 v) = 0; + + virtual void WriteInt16(int16 v) = 0; + virtual void WriteUInt16(uint16 v) = 0; + + virtual void WriteInt32(int32 v) = 0; + virtual void WriteUInt32(uint32 v) = 0; + + virtual void WriteInt64(int64 v) = 0; + virtual void WriteUInt64(uint64 v) = 0; + + virtual void WriteFloat(float v) = 0; + virtual void WriteDouble(double v) = 0; + + virtual void WriteString(const char* s) = 0; + + virtual void WriteBuffer(const void* data ,unsigned int len) = 0; + +}; diff --git a/metamod/include/engine/Sequence.h b/metamod/include/engine/Sequence.h new file mode 100644 index 0000000..6253018 --- /dev/null +++ b/metamod/include/engine/Sequence.h @@ -0,0 +1,201 @@ +//--------------------------------------------------------------------------- +// +// S c r i p t e d S e q u e n c e s +// +//--------------------------------------------------------------------------- +#ifndef _INCLUDE_SEQUENCE_H_ +#define _INCLUDE_SEQUENCE_H_ + + +#ifndef _DEF_BYTE_ +typedef unsigned char byte; +#endif + +//--------------------------------------------------------------------------- +// client_textmessage_t +//--------------------------------------------------------------------------- +typedef struct client_textmessage_s +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + const char *pName; + const char *pMessage; +} client_textmessage_t; + + +//-------------------------------------------------------------------------- +// sequenceDefaultBits_e +// +// Enumerated list of possible modifiers for a command. This enumeration +// is used in a bitarray controlling what modifiers are specified for a command. +//--------------------------------------------------------------------------- +enum sequenceModifierBits +{ + SEQUENCE_MODIFIER_EFFECT_BIT = (1 << 1), + SEQUENCE_MODIFIER_POSITION_BIT = (1 << 2), + SEQUENCE_MODIFIER_COLOR_BIT = (1 << 3), + SEQUENCE_MODIFIER_COLOR2_BIT = (1 << 4), + SEQUENCE_MODIFIER_FADEIN_BIT = (1 << 5), + SEQUENCE_MODIFIER_FADEOUT_BIT = (1 << 6), + SEQUENCE_MODIFIER_HOLDTIME_BIT = (1 << 7), + SEQUENCE_MODIFIER_FXTIME_BIT = (1 << 8), + SEQUENCE_MODIFIER_SPEAKER_BIT = (1 << 9), + SEQUENCE_MODIFIER_LISTENER_BIT = (1 << 10), + SEQUENCE_MODIFIER_TEXTCHANNEL_BIT = (1 << 11), +}; +typedef enum sequenceModifierBits sequenceModifierBits_e ; + + +//--------------------------------------------------------------------------- +// sequenceCommandEnum_e +// +// Enumerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandEnum_ +{ + SEQUENCE_COMMAND_ERROR = -1, + SEQUENCE_COMMAND_PAUSE = 0, + SEQUENCE_COMMAND_FIRETARGETS, + SEQUENCE_COMMAND_KILLTARGETS, + SEQUENCE_COMMAND_TEXT, + SEQUENCE_COMMAND_SOUND, + SEQUENCE_COMMAND_GOSUB, + SEQUENCE_COMMAND_SENTENCE, + SEQUENCE_COMMAND_REPEAT, + SEQUENCE_COMMAND_SETDEFAULTS, + SEQUENCE_COMMAND_MODIFIER, + SEQUENCE_COMMAND_POSTMODIFIER, + SEQUENCE_COMMAND_NOOP, + + SEQUENCE_MODIFIER_EFFECT, + SEQUENCE_MODIFIER_POSITION, + SEQUENCE_MODIFIER_COLOR, + SEQUENCE_MODIFIER_COLOR2, + SEQUENCE_MODIFIER_FADEIN, + SEQUENCE_MODIFIER_FADEOUT, + SEQUENCE_MODIFIER_HOLDTIME, + SEQUENCE_MODIFIER_FXTIME, + SEQUENCE_MODIFIER_SPEAKER, + SEQUENCE_MODIFIER_LISTENER, + SEQUENCE_MODIFIER_TEXTCHANNEL, +}; +typedef enum sequenceCommandEnum_ sequenceCommandEnum_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandType_e +// +// Typeerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandType_ +{ + SEQUENCE_TYPE_COMMAND, + SEQUENCE_TYPE_MODIFIER, +}; +typedef enum sequenceCommandType_ sequenceCommandType_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandMapping_s +// +// A mapping of a command enumerated-value to its name. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandMapping_ sequenceCommandMapping_s; +struct sequenceCommandMapping_ +{ + sequenceCommandEnum_e commandEnum; + const char* commandName; + sequenceCommandType_e commandType; +}; + + +//--------------------------------------------------------------------------- +// sequenceCommandLine_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandLine_ sequenceCommandLine_s; +struct sequenceCommandLine_ +{ + int commandType; // Specifies the type of command + client_textmessage_t clientMessage; // Text HUD message struct + char* speakerName; // Targetname of speaking entity + char* listenerName; // Targetname of entity being spoken to + char* soundFileName; // Name of sound file to play + char* sentenceName; // Name of sentences.txt to play + char* fireTargetNames; // List of targetnames to fire + char* killTargetNames; // List of targetnames to remove + float delay; // Seconds 'till next command + int repeatCount; // If nonzero, reset execution pointer to top of block (N times, -1 = infinite) + int textChannel; // Display channel on which text message is sent + int modifierBitField; // Bit field to specify what clientmessage fields are valid + sequenceCommandLine_s* nextCommandLine; // Next command (linked list) +}; + + +//--------------------------------------------------------------------------- +// sequenceEntry_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceEntry_ sequenceEntry_s; +struct sequenceEntry_ +{ + char* fileName; // Name of sequence file without .SEQ extension + char* entryName; // Name of entry label in file + sequenceCommandLine_s* firstCommand; // Linked list of commands in entry + sequenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? +}; + + + +//--------------------------------------------------------------------------- +// sentenceEntry_s +// Structure representing a single sentence of a group from a .SEQ +// file entry. Sentences are identical to entries in sentences.txt, but +// can be unique per level and are loaded/unloaded with the level. +//--------------------------------------------------------------------------- +typedef struct sentenceEntry_ sentenceEntry_s; +struct sentenceEntry_ +{ + char* data; // sentence data (ie "We have hostiles" ) + sentenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? + unsigned int index; // this entry's position in the file. +}; + +//-------------------------------------------------------------------------- +// sentenceGroupEntry_s +// Structure representing a group of sentences found in a .SEQ file. +// A sentence group is defined by all sentences with the same name, ignoring +// the number at the end of the sentence name. Groups enable a sentence +// to be picked at random across a group. +//-------------------------------------------------------------------------- +typedef struct sentenceGroupEntry_ sentenceGroupEntry_s; +struct sentenceGroupEntry_ +{ + char* groupName; // name of the group (ie CT_ALERT ) + unsigned int numSentences; // number of sentences in group + sentenceEntry_s* firstSentence; // head of linked list of sentences in group + sentenceGroupEntry_s* nextEntry; // next loaded group +}; + +//--------------------------------------------------------------------------- +// Function declarations +//--------------------------------------------------------------------------- +sequenceEntry_s* SequenceGet( const char* fileName, const char* entryName ); +void Sequence_ParseFile( const char* fileName, qboolean isGlobal ); +void Sequence_OnLevelLoad( const char* mapName ); +sentenceEntry_s* SequencePickSentence( const char *groupName, int pickMethod, int *picked ); + +#endif /* _INCLUDE_SEQUENCE_H_ */ diff --git a/metamod/include/engine/archtypes.h b/metamod/include/engine/archtypes.h new file mode 100644 index 0000000..e528a6d --- /dev/null +++ b/metamod/include/engine/archtypes.h @@ -0,0 +1,66 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/#ifndef ARCHTYPES_H +#define ARCHTYPES_H + +#ifdef __x86_64__ +#define X64BITS +#endif + +#if defined( _WIN32 ) && (! defined( __MINGW32__ )) + +typedef __int8 int8; +typedef unsigned __int8 uint8; +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; +typedef __int32 intp; // intp is an integer that can accomodate a pointer +typedef unsigned __int32 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) + +#else /* _WIN32 */ +typedef char int8; +typedef unsigned char uint8; +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + +#endif /* else _WIN32 */ + +#endif /* ARCHTYPES_H */ diff --git a/metamod/include/engine/bspfile.h b/metamod/include/engine/bspfile.h new file mode 100644 index 0000000..fd3ae92 --- /dev/null +++ b/metamod/include/engine/bspfile.h @@ -0,0 +1,169 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define BSPVERSION 30 +#define MAX_MAP_HULLS 4 + +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + +#define CONTENTS_TRANSLUCENT -15 + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 + +#define HEADER_LUMPS 15 + +/* ../engine/bspfile.h:41 */ +typedef struct lump_s +{ + int fileofs; + int filelen; +} lump_t; + +/* ../engine/bspfile.h:64 */ +typedef struct dmodel_s +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +/* ../engine/bspfile.h:73 */ +typedef struct dheader_s +{ + int version; + lump_t lumps[15]; +} dheader_t; + +/* <485b2> ../engine/bspfile.h:79 */ +typedef struct dmiptexlump_s +{ + int _nummiptex; + int dataofs[4]; +} dmiptexlump_t; + +/* <1ce18> ../engine/bspfile.h:86 */ +typedef struct miptex_s +{ + char name[16]; + unsigned width; + unsigned height; + unsigned offsets[4]; +} miptex_t; + +/* <48652> ../engine/bspfile.h:94 */ +typedef struct dvertex_s +{ + float point[3]; +} dvertex_t; + +/* <48674> ../engine/bspfile.h:110 */ +typedef struct dplane_s +{ + float normal[3]; + float dist; + int type; +} dplane_t; + +/* <486b2> ../engine/bspfile.h:132 */ +typedef struct dnode_s +{ + int planenum; + short children[2]; + short mins[3]; + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; +} dnode_t; + +/* ../engine/bspfile.h:142 */ +typedef struct dclipnode_s +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +/* <4876a> ../engine/bspfile.h:149 */ +typedef struct texinfo_s +{ + float vecs[2][4]; + int _miptex; + int flags; +} texinfo_t; + +/* <487c2> ../engine/bspfile.h:159 */ +typedef struct dedge_s +{ + unsigned short v[2]; +} dedge_t; + +/* <487f2> ../engine/bspfile.h:165 */ +typedef struct dface_s +{ + short planenum; + short side; + int firstedge; + short numedges; + short texinfo; + byte styles[4]; + int lightofs; +} dface_t; + +typedef struct dleaf_s +{ + int contents; + int visofs; + short mins[3]; + short maxs[3]; + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + byte ambient_level[4]; +} dleaf_t; diff --git a/metamod/include/engine/cmd_rehlds.h b/metamod/include/engine/cmd_rehlds.h new file mode 100644 index 0000000..9302f63 --- /dev/null +++ b/metamod/include/engine/cmd_rehlds.h @@ -0,0 +1,50 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "archtypes.h" + +typedef void(*xcommand_t)(void); + +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; + int flags; +} cmd_function_t; + +typedef enum cmd_source_s +{ + src_client = 0, // came in over a net connection as a clc_stringcmd. host_client will be valid during this state. + src_command = 1, // from the command buffer. +} cmd_source_t; + +#define FCMD_HUD_COMMAND BIT(0) +#define FCMD_GAME_COMMAND BIT(1) +#define FCMD_WRAPPER_COMMAND BIT(2) diff --git a/metamod/include/engine/common_rehlds.h b/metamod/include/engine/common_rehlds.h new file mode 100644 index 0000000..c0f4c39 --- /dev/null +++ b/metamod/include/engine/common_rehlds.h @@ -0,0 +1,73 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "const.h" +#include "qlimits.h" + +// Don't allow overflow +#define SIZEBUF_CHECK_OVERFLOW 0 +#define SIZEBUF_ALLOW_OVERFLOW BIT(0) +#define SIZEBUF_OVERFLOWED BIT(1) + +#define MAX_NUM_ARGVS 50 +#define NUM_SAFE_ARGVS 7 + +#define COM_COPY_CHUNK_SIZE 1024 +#define COM_MAX_CMD_LINE 256 + +typedef struct sizebuf_s +{ + const char *buffername; + uint16 flags; + byte *data; + int maxsize; + int cursize; +} sizebuf_t; + +typedef struct downloadtime_s +{ + qboolean bUsed; + float fTime; + int nBytesRemaining; +} downloadtime_t; + +typedef struct incomingtransfer_s +{ + qboolean doneregistering; + int percent; + qboolean downloadrequested; + downloadtime_t rgStats[8]; + int nCurStat; + int nTotalSize; + int nTotalToTransfer; + int nRemainingToTransfer; + float fLastStatusUpdate; + qboolean custom; +} incomingtransfer_t; diff --git a/metamod/include/engine/crc32c.cpp b/metamod/include/engine/crc32c.cpp new file mode 100644 index 0000000..1220c50 --- /dev/null +++ b/metamod/include/engine/crc32c.cpp @@ -0,0 +1,143 @@ +/* +Copyright (C) 2010 by Ronnie Sahlberg +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, see . +*/ + +#include "crc32c.h" +#include "sys_shared.h" +#include "immintrin.h" + +/*****************************************************************/ +/* */ +/* CRC LOOKUP TABLE */ +/* ================ */ +/* The following CRC lookup table was generated automagically */ +/* by the Rocksoft^tm Model CRC Algorithm Table Generation */ +/* Program V1.0 using the following model parameters: */ +/* */ +/* Width : 4 bytes. */ +/* Poly : 0x1EDC6F41L */ +/* Reverse : TRUE. */ +/* */ +/* For more information on the Rocksoft^tm Model CRC Algorithm, */ +/* see the document titled "A Painless Guide to CRC Error */ +/* Detection Algorithms" by Ross Williams */ +/* (ross@guest.adelaide.edu.au.). This document is likely to be */ +/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/*****************************************************************/ + +static uint32 crctable[256] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, + 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, + 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, + 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, + 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, + 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, + 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, + 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, + 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, + 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, + 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, + 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, + 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, + 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, + 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, + 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, + 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, + 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, + 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, + 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, + 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, + 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, + 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, + 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, + 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, + 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, + 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, + 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, + 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, + 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, + 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, + 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, + 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, + 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, + 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, + 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, + 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, + 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, + 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, + 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, + 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, + 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, + 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, + 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, + 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, + 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, + 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, + 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, + 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, + 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, + 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, + 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, + 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, + 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, + 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, + 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, + 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, + 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, + 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, + 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, + 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, + 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, + 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L +}; + +uint32 crc32c_t8_nosse(uint32 iCRC, uint8 u8) { + return (iCRC >> 8) ^ crctable[(iCRC ^ u8) & 0xFF]; +} + +uint32 crc32c_t_nosse(uint32 iCRC, const uint8 *buf, int len) { + uint32 crc = iCRC; + while (len-- > 0) { + crc = (crc >> 8) ^ crctable[(crc ^ (*buf++)) & 0xFF]; + } + return crc; +} + +uint32 crc32c_t8_sse(uint32 iCRC, uint8 u8) { + return _mm_crc32_u8(iCRC, u8); +} + +uint32 crc32c_t_sse(uint32 iCRC, const uint8 *buf, unsigned int len) { + uint32 crc32cval = iCRC; + unsigned int i = 0; + + for (; i < (len >> 2); i += 4) { + crc32cval = _mm_crc32_u32(crc32cval, *(uint32*)&buf[i]); + } + + for (; i < len; i++) { + crc32cval = _mm_crc32_u8(crc32cval, buf[i]); + } + + return crc32cval; +} + +uint32 crc32c_t(uint32 iCRC, const uint8 *buf, unsigned int len) { + return cpuinfo.sse4_2 ? crc32c_t_sse(iCRC, buf, len) : crc32c_t_nosse(iCRC, buf, len); +} + +uint32 crc32c(const uint8 *buf, int len) { + return crc32c_t(0xffffffff, buf, len); +} diff --git a/metamod/include/engine/crc32c.h b/metamod/include/engine/crc32c.h new file mode 100644 index 0000000..892919b --- /dev/null +++ b/metamod/include/engine/crc32c.h @@ -0,0 +1,22 @@ +/* +Copyright (C) 2010 by Ronnie Sahlberg +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. +You should have received a copy of the GNU Lesser General Public License +along with this program; if not, see . +*/ +#pragma once +#include "archtypes.h" + +extern uint32 crc32c_t8_nosse(uint32 iCRC, uint8 u8); +extern uint32 crc32c_t8_sse(uint32 iCRC, uint8 u8); +extern uint32 crc32c_t_nosse(uint32 iCRC, const uint8 *buf, int len); +extern uint32 crc32c_t_sse(uint32 iCRC, const uint8 *buf, unsigned int len); +extern uint32 crc32c_t(uint32 iCRC, const uint8 *buf, unsigned int len); +extern uint32 crc32c(const uint8 *buf, int len); diff --git a/sdk/engine/custom.h b/metamod/include/engine/custom.h similarity index 85% rename from sdk/engine/custom.h rename to metamod/include/engine/custom.h index 242dae6..5a5156e 100644 --- a/sdk/engine/custom.h +++ b/metamod/include/engine/custom.h @@ -13,18 +13,12 @@ * ****/ // Customization.h - -#ifndef CUSTOM_H -#define CUSTOM_H -#ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ -#endif #include "const.h" #define MAX_QPATH 64 // Must match value in quakedefs.h +#define MAX_RESOURCE_LIST 1280 ///////////////// // Customization @@ -39,6 +33,9 @@ typedef enum t_generic, t_eventscript, t_world, // Fake type for world, is really t_model + rt_unk, + + rt_max } resourcetype_t; @@ -49,7 +46,7 @@ typedef struct typedef struct resourceinfo_s { - _resourceinfo_t info[ 8 ]; + _resourceinfo_t info[ rt_max ]; } resourceinfo_t; #define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. @@ -58,7 +55,8 @@ typedef struct resourceinfo_s // or is it a server startup resource. #define RES_REQUESTED (1<<3) // Already requested a download of this one #define RES_PRECACHED (1<<4) // Already precached -#define RES_ALWAYS (1<<5) // download always even if available on client +#define RES_ALWAYS (1<<5) // download always even if available on client +#define RES_UNK_6 (1<<6) // TODO: what is it? #define RES_CHECKFILE (1<<7) // check file on client #include "crc.h" @@ -96,10 +94,3 @@ typedef struct customization_s #define FCUST_FROMHPAK ( 1<<0 ) #define FCUST_WIPEDATA ( 1<<1 ) #define FCUST_IGNOREINIT ( 1<<2 ) - -void COM_ClearCustomizationList( struct customization_s *pHead, qboolean bCleanDecals); -qboolean COM_CreateCustomization( struct customization_s *pListHead, struct resource_s *pResource, int playernumber, int flags, - struct customization_s **pCustomization, int *nLumps ); -int COM_SizeofResourceList ( struct resource_s *pList, struct resourceinfo_s *ri ); - -#endif // CUSTOM_H diff --git a/sdk/engine/customentity.h b/metamod/include/engine/customentity.h similarity index 100% rename from sdk/engine/customentity.h rename to metamod/include/engine/customentity.h diff --git a/metamod/include/engine/d_local.h b/metamod/include/engine/d_local.h new file mode 100644 index 0000000..8bf396d --- /dev/null +++ b/metamod/include/engine/d_local.h @@ -0,0 +1,46 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + + + +/* <82286> ../engine/d_local.h:20 */ +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; + int lightadj[4]; + int dlight; + int size; + unsigned width; + unsigned height; + float mipscale; + struct texture_s *texture; + unsigned char data[4]; +} surfcache_t; diff --git a/sdk/engine/edict.h b/metamod/include/engine/edict.h similarity index 94% rename from sdk/engine/edict.h rename to metamod/include/engine/edict.h index 129cdfc..9a38993 100644 --- a/sdk/engine/edict.h +++ b/metamod/include/engine/edict.h @@ -8,9 +8,7 @@ #if !defined EDICT_H #define EDICT_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif #define MAX_ENT_LEAFS 48 diff --git a/sdk/engine/eiface.h b/metamod/include/engine/eiface.h similarity index 91% rename from sdk/engine/eiface.h rename to metamod/include/engine/eiface.h index b79a5dd..85065b7 100644 --- a/sdk/engine/eiface.h +++ b/metamod/include/engine/eiface.h @@ -12,8 +12,7 @@ * without written permission from Valve LLC. * ****/ -#ifndef EIFACE_H -#define EIFACE_H +#pragma once #include "archtypes.h" // DAL @@ -44,36 +43,36 @@ #endif */ -typedef enum - { +enum ALERT_TYPE +{ at_notice, at_console, // same as at_notice, but forces a ConPrintf, not a message box at_aiconsole, // same as at_console, but only shown if developer level is 2! at_warning, at_error, at_logged // Server print to console ( only in multiplayer games ). - } ALERT_TYPE; +}; // 4-22-98 JOHN: added for use in pfnClientPrintf -typedef enum - { +enum PRINT_TYPE +{ print_console, print_center, print_chat, - } PRINT_TYPE; +}; // For integrity checking of content on clients -typedef enum +enum FORCE_TYPE { force_exactfile, // File on client must exactly match server's file force_model_samebounds, // For model files only, the geometry must fit in the same bbox force_model_specifybounds, // For model files only, the geometry must fit in the specified bbox force_model_specifybounds_if_avail, // For Steam model files only, the geometry must fit in the specified bbox (if the file is available) -} FORCE_TYPE; +}; // Returned by TraceLine -typedef struct - { +struct TraceResult +{ int fAllSolid; // if true, plane is not valid int fStartSolid; // if true, the initial point was in a solid area int fInOpen; @@ -84,7 +83,7 @@ typedef struct vec3_t vecPlaneNormal; // surface normal at impact edict_t *pHit; // entity the surface is on int iHitgroup; // 0 == generic, non zero is specific body part - } TraceResult; +}; // CD audio status typedef struct @@ -95,7 +94,7 @@ typedef struct int fEnabled; int fPlayLooping; float cdvolume; - //BYTE remap[100]; + //byte remap[100]; int fCDRom; int fPlayTrack; } CDStatus; @@ -145,11 +144,11 @@ typedef struct enginefuncs_s const char *(*pfnTraceTexture) (edict_t *pTextureEntity, const float *v1, const float *v2 ); void (*pfnTraceSphere) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); void (*pfnGetAimVector) (edict_t* ent, float speed, float *rgflReturn); - void (*pfnServerCommand) (const char* str); + void (*pfnServerCommand) (char* str); void (*pfnServerExecute) (void); - void (*pfnClientCommand) (edict_t* pEdict, const char* szFmt, ...); + void (*pfnClientCommand) (edict_t* pEdict, char* szFmt, ...); void (*pfnParticleEffect) (const float *org, const float *dir, float color, float count); - void (*pfnLightStyle) (int style, const char* val); + void (*pfnLightStyle) (int style, char* val); int (*pfnDecalIndex) (const char *name); int (*pfnPointContents) (const float *rgflVector); void (*pfnMessageBegin) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); @@ -201,14 +200,14 @@ typedef struct enginefuncs_s void (*pfnSetView) (const edict_t *pClient, const edict_t *pViewent ); float (*pfnTime) ( void ); void (*pfnCrosshairAngle) (const edict_t *pClient, float pitch, float yaw); - byte * (*pfnLoadFileForMe) (const char *filename, int *pLength); + byte * (*pfnLoadFileForMe) (char *filename, int *pLength); void (*pfnFreeFile) (void *buffer); void (*pfnEndSection) (const char *pszSectionName); // trigger_endsection int (*pfnCompareFileTime) (char *filename1, char *filename2, int *iCompare); void (*pfnGetGameDir) (char *szGetGameDir); void (*pfnCvar_RegisterVariable) (cvar_t *variable); void (*pfnFadeClientVolume) (const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); - void (*pfnSetClientMaxspeed) (const edict_t *pEdict, float fNewMaxspeed); + void (*pfnSetClientMaxspeed) (edict_t *pEdict, float fNewMaxspeed); edict_t * (*pfnCreateFakeClient) (const char *netname); // returns NULL if fake client can't be created void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); int (*pfnNumberOfEntities) (void); @@ -216,9 +215,9 @@ typedef struct enginefuncs_s char* (*pfnInfoKeyValue) (char *infobuffer, const char *key); void (*pfnSetKeyValue) (char *infobuffer, const char *key, const char *value); void (*pfnSetClientKeyValue) (int clientIndex, char *infobuffer, const char *key, const char *value); - int (*pfnIsMapValid) (const char *filename); + int (*pfnIsMapValid) (char *filename); void (*pfnStaticDecal) ( const float *origin, int decalIndex, int entityIndex, int modelIndex ); - int (*pfnPrecacheGeneric) (const char* s); + int (*pfnPrecacheGeneric) (char* s); int (*pfnGetPlayerUserId) (edict_t *e ); // returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients void (*pfnBuildSoundMsg) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); int (*pfnIsDedicatedServer) (void);// is this a dedicated server? @@ -230,17 +229,17 @@ typedef struct enginefuncs_s const char *(*pfnGetPhysicsKeyValue) ( const edict_t *pClient, const char *key ); void (*pfnSetPhysicsKeyValue) ( const edict_t *pClient, const char *key, const char *value ); const char *(*pfnGetPhysicsInfoString) ( const edict_t *pClient ); - unsigned short (*pfnPrecacheEvent) ( int type, const char* psz ); + unsigned short (*pfnPrecacheEvent) ( int type, const char*psz ); void (*pfnPlaybackEvent) ( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); unsigned char *(*pfnSetFatPVS) ( float *org ); unsigned char *(*pfnSetFatPAS) ( float *org ); - int (*pfnCheckVisibility ) ( const edict_t *entity, unsigned char *pset ); + int (*pfnCheckVisibility ) ( edict_t *entity, unsigned char *pset ); void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); void (*pfnDeltaUnsetField) ( struct delta_s *pFields, const char *fieldname ); - void (*pfnDeltaAddEncoder) ( const char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); + void (*pfnDeltaAddEncoder) ( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); int (*pfnGetCurrentPlayer) ( void ); int (*pfnCanSkipPlayer) ( const edict_t *player ); int (*pfnDeltaFindField) ( struct delta_s *pFields, const char *fieldname ); @@ -259,7 +258,7 @@ typedef struct enginefuncs_s void (*pfnGetPlayerStats) ( const edict_t *pClient, int *ping, int *packet_loss ); - void (*pfnAddServerCommand) ( const char *cmd_name, void (*function) (void) ); + void (*pfnAddServerCommand) ( char *cmd_name, void (*function) (void) ); // For voice communications, set which clients hear eachother. // NOTE: these functions take player entity indices (starting at 1). @@ -275,7 +274,7 @@ typedef struct enginefuncs_s sentenceEntry_s* (*pfnSequencePickSentence) ( const char* groupName, int pickMethod, int *picked ); // LH: Give access to filesize via filesystem - int (*pfnGetFileSize) ( const char *filename ); + int (*pfnGetFileSize) ( char *filename ); unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath); // MDC: Added for CZ career-mode @@ -291,14 +290,16 @@ typedef struct enginefuncs_s int (*pfnGetTimesTutorMessageShown) (int mid); void (*pfnProcessTutorMessageDecayBuffer) (int *buffer, int bufferLength); void (*pfnConstructTutorMessageDecayBuffer) (int *buffer, int bufferLength); - void (*pfnResetTutorMessageDecayData) ( void ); - void (*pfnQueryClientCvarValue) ( const edict_t *player, const char *cvarName ); - void (*pfnQueryClientCvarValue2) ( const edict_t *player, const char *cvarName, int requestID ); - int (*pfnCheckParm) ( const char *pchCmdLineToken, char **ppnext ); -#ifdef __METAMOD_BUILD__ - //extra (future updates) - void * extra_functions[16]; -#endif /*__METAMOD_BUILD__*/ + void (*pfnResetTutorMessageDecayData) ( void ); + + // Added 2005/08/11 (no SDK update): + void(*pfnQueryClientCvarValue) (const edict_t *player, const char *cvarName); + + // Added 2005/11/21 (no SDK update): + void(*pfnQueryClientCvarValue2) (const edict_t *player, const char *cvarName, int requestID); + + // Added 2009/06/19 (no SDK update): + int(*pfnEngCheckParm) (const char *pchCmdLineToken, char **ppnext); } enginefuncs_t; @@ -307,10 +308,10 @@ typedef struct enginefuncs_s // Passed to pfnKeyValue typedef struct KeyValueData_s { - const char *szClassName; // in: entity classname - const char *szKeyName; // in: name of key - const char *szValue; // in: value of key - int32 fHandled; // out: DLL sets to true if key-value pair was understood + char *szClassName; // in: entity classname + char *szKeyName; // in: name of key + char *szValue; // in: value of key + qboolean fHandled; // out: DLL sets to true if key-value pair was understood } KeyValueData; @@ -318,7 +319,7 @@ typedef struct { char mapName[ 32 ]; char landmarkName[ 32 ]; - edict_t *pentLandmark; + edict_t *pentLandmark; vec3_t vecLandmarkOrigin; } LEVELLIST; #define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of ENTITYTABLE->flags @@ -397,7 +398,7 @@ typedef enum _fieldtypes FIELD_TYPECOUNT, // MUST BE LAST } FIELDTYPE; -#if !defined(offsetof) && !defined(GNUC) +#if !defined(offsetof) && !defined(GNUC) #define offsetof(s,m) (size_t)&(((s *)0)->m) #endif @@ -414,15 +415,15 @@ typedef enum _fieldtypes typedef struct { FIELDTYPE fieldType; - const char *fieldName; + char *fieldName; int fieldOffset; short fieldSize; short flags; } TYPEDESCRIPTION; -// Fix warning in MSVC8 -#undef ARRAYSIZE +#ifndef ARRAYSIZE #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) +#endif typedef struct { @@ -479,7 +480,7 @@ typedef struct void (*pfnPM_Move) ( struct playermove_s *ppmove, qboolean server ); void (*pfnPM_Init) ( struct playermove_s *ppmove ); - char (*pfnPM_FindTextureType)( const char *name ); + char (*pfnPM_FindTextureType)( char *name ); void (*pfnSetupVisibility)( struct edict_s *pViewEntity, struct edict_s *pClient, unsigned char **pvs, unsigned char **pas ); void (*pfnUpdateClientData) ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); int (*pfnAddToFullPack)( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); @@ -492,7 +493,7 @@ typedef struct // Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max // size of the response_buffer, so you must zero it out if you choose not to respond. - int (*pfnConnectionlessPacket ) ( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); + int (*pfnConnectionlessPacket ) ( const struct netadr_s *net_from_, const char *args, char *response_buffer, int *response_buffer_size ); // Enumerates player hulls. Returns 0 if the hull number doesn't exist, 1 otherwise int (*pfnGetHullBounds) ( int hullnumber, float *mins, float *maxs ); @@ -526,12 +527,10 @@ typedef struct void (*pfnCvarValue)( const edict_t *pEnt, const char *value ); void (*pfnCvarValue2)( const edict_t *pEnt, int requestID, const char *cvarName, const char *value ); } NEW_DLL_FUNCTIONS; -typedef int (*NEW_DLL_FUNCTIONS_FN)( NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); +typedef int(*NEW_DLL_FUNCTIONS_FN)(NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion); // Pointers will be null if the game DLL doesn't support this API. extern NEW_DLL_FUNCTIONS gNewDLLFunctions; -typedef int (*APIFUNCTION)( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); -typedef int (*APIFUNCTION2)( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); - -#endif /* EIFACE_H */ +typedef int(*APIFUNCTION)(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion); +typedef int(*APIFUNCTION2)(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion); diff --git a/metamod/include/engine/keydefs.h b/metamod/include/engine/keydefs.h new file mode 100644 index 0000000..ef9b2fc --- /dev/null +++ b/metamod/include/engine/keydefs.h @@ -0,0 +1,131 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// keydefs.h +#ifndef KEYDEFS_H +#define KEYDEFS_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_KP_HOME 160 +#define K_KP_UPARROW 161 +#define K_KP_PGUP 162 +#define K_KP_LEFTARROW 163 +#define K_KP_5 164 +#define K_KP_RIGHTARROW 165 +#define K_KP_END 166 +#define K_KP_DOWNARROW 167 +#define K_KP_PGDN 168 +#define K_KP_ENTER 169 +#define K_KP_INS 170 +#define K_KP_DEL 171 +#define K_KP_SLASH 172 +#define K_KP_MINUS 173 +#define K_KP_PLUS 174 +#define K_CAPSLOCK 175 + + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 +#define K_MWHEELDOWN 239 +#define K_MWHEELUP 240 + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 241 +#define K_MOUSE2 242 +#define K_MOUSE3 243 +#define K_MOUSE4 244 +#define K_MOUSE5 245 + +#endif // KEYDEFS_H diff --git a/metamod/include/engine/maintypes.h b/metamod/include/engine/maintypes.h new file mode 100644 index 0000000..40ae20c --- /dev/null +++ b/metamod/include/engine/maintypes.h @@ -0,0 +1,52 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MAINTYPES_H +#define MAINTYPES_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "osconfig.h" +#include "mathlib.h" + + +// Has no references on server side. +#define NOXREF +// Function body is not implemented. +#define NOBODY +// Function is not tested at all. +#define UNTESTED + +#define BIT(n) (1<<(n)) + + +typedef unsigned int string_t; // from engine's pr_comp.h; + +#endif // MAINTYPES_H diff --git a/metamod/include/engine/model.h b/metamod/include/engine/model.h new file mode 100644 index 0000000..2c155d5 --- /dev/null +++ b/metamod/include/engine/model.h @@ -0,0 +1,415 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "const.h" +#include "modelgen.h" +#include "spritegn.h" +#include "bspfile.h" +#include "crc.h" +#include "com_model.h" + +#define SURF_PLANEBACK 2 +#define SURF_DRAWSKY 4 +#define SURF_DRAWSPRITE 8 +#define SURF_DRAWTURB 0x10 +#define SURF_DRAWTILED 0x20 +#define SURF_DRAWBACKGROUND 0x40 +#define ALIAS_MODEL_VERSION 0x006 + +#define MAX_MODEL_NAME 64 +#define MIPLEVELS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds +#define MAXLIGHTMAPS 4 +#define MAX_KNOWN_MODELS 1024 + +/* <6816> ../engine/model.h:27 */ +typedef struct mvertex_s +{ + vec3_t position; +} mvertex_t; + +/* <6838> ../engine/model.h:39 */ +typedef struct mplane_s +{ + vec3_t normal; // surface normal + float dist; // closest appoach to origin + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +/* <68a6> ../engine/model.h:48 */ +typedef struct texture_s +{ + char name[16]; + unsigned width, height; + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frame 1 use these + unsigned offsets[MIPLEVELS]; // four mip maps stored + unsigned paloffset; +} texture_t; + +/* <6950> ../engine/model.h:71 */ +typedef struct medge_s +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +/* <697e> ../engine/model.h:78 */ +typedef struct mtexinfo_s +{ + float vecs[2][4]; // [s/t] unit vectors in world space. + // [i][3] is the s/t offset relative to the origin. + // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] + float mipadjust; // ?? mipmap limits for very small surfaces + texture_t *texture; + int flags; // sky or slime, no lightmap or 256 subdivision +} mtexinfo_t; +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision + +/* <69d0> ../engine/model.h:91 */ +typedef struct msurface_s msurface_t; +/* <1db66> ../engine/model.h:92 */ +typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +/* <1db71> ../engine/model.h:96 */ +struct decal_s +{ + decal_t *pnext; // linked list for each surface + msurface_t *psurface; // Surface id for persistence / unlinking + short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) + short dy; + short texture; // Decal texture + byte scale; // Pixel scale + byte flags; // Decal flags + + short entityIndex; // Entity this is attached to +}; + +/* <69db> ../engine/model.h:118 */ +struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + int dlightframe; // last frame the surface was checked by an animated light + int dlightbits; // dynamically generated. Indicates if the surface illumination + // is modified by an animated light. + + mplane_t *plane; // pointer to shared plane + int flags; // see SURF_ #defines + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + + // surface generation data + struct surfcache_s *cachespots[MIPLEVELS]; + + short texturemins[2]; // smallest s/t position on the surface. + short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces + + mtexinfo_t *texinfo; + + // lighting info + byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights + // no one surface can be effected by more than 4 + // animated lights. + color24 *samples; + + decal_t *pdecals; +}; + +/* <6b6c> ../engine/model.h:149 */ +typedef struct mnode_s +{ + // common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + + // node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + +/* <1dcd4> ../engine/model.h:169 */ +typedef struct mleaf_s +{ + // common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + + // leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_t; + +/* <1ddbe> ../engine/model.h:190 */ +typedef struct hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins, clip_maxs; +} hull_t; + +/* <4b3fe> ../engine/model.h:210 */ +typedef struct mspriteframe_t +{ + int width; + int height; + void *pcachespot; + float up, down, left, right; + byte pixels[4]; +} mspriteframe_s; + +/* <4b485> ../engine/model.h:219 */ +typedef struct mspritegroup_s +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +/* <4b4df> ../engine/model.h:226 */ +typedef struct mspriteframedesc_s +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +/* <4b50f> ../engine/model.h:232 */ +typedef struct msprite_s +{ + short int type; + short int texFormat; + int maxwidth, maxheight; + int numframes; + int paloffset; + float beamlength; + void *cachespot; + mspriteframedesc_t frames[1]; +} msprite_t; + +/* <4b5b5> ../engine/model.h:255 */ +typedef struct maliasframedesc_s +{ + aliasframetype_t type; + trivertx_t bboxmin, bboxmax; + int frame; + char name[16]; +} maliasframedesc_t; + +/* <4b615> ../engine/model.h:264 */ +typedef struct maliasskindesc_s +{ + aliasskintype_t type; + void *pcachespot; + int skin; +} maliasskindesc_t; + +/* <4b658> ../engine/model.h:271 */ +typedef struct maliasgroupframedesc_s +{ + trivertx_t bboxmin, bboxmax; + int frame; +} maliasgroupframedesc_t; + +/* <4b69b> ../engine/model.h:278 */ +typedef struct maliasgroup_s +{ + int numframes; + int intervals; + maliasgroupframedesc_t frames[1]; +} maliasgroup_t; + +/* <4b6ee> ../engine/model.h:285 */ +typedef struct maliasskingroup_s +{ + int numskins; + int intervals; + maliasskindesc_t skindescs[1]; +} maliasskingroup_t; + +/* <4b741> ../engine/model.h:293 */ +typedef struct mtriangle_s +{ + int facesfront; + int vertindex[3]; +} mtriangle_t; + +/* <4b779> ../engine/model.h:298 */ +typedef struct aliashdr_s +{ + int model; + int stverts; + int skindesc; + int triangles; + int palette; + maliasframedesc_t frames[1]; +} aliashdr_t; + +/* <1de30> ../engine/model.h:315 */ +typedef enum modtype_e +{ + mod_brush, + mod_sprite, + mod_alias, + mod_studio, +} modtype_t; + +/* <1de5e> ../engine/model.h:331 */ +typedef struct model_s +{ + char name[MAX_MODEL_NAME]; + + //TODO: qboolean? seriously? + int needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + + // + // volume occupied by the model + // + vec3_t mins, maxs; + float radius; + + // + // brush model + // + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + struct mleaf_s *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + + color24 *lightdata; + + char *entities; + + // + // additional model data + // + cache_user_t cache; // only access through Mod_Extradata +} model_t; + +typedef struct cachepic_s +{ + char name[64]; + cache_user_t cache; +} cachepic_t; + +typedef struct cachewad_s cachewad_t; + +typedef void(*PFNCACHE)(cachewad_t *, unsigned char *); + +typedef struct cachewad_s +{ + char *name; + cachepic_t *cache; + int cacheCount; + int cacheMax; + struct lumpinfo_s *lumps; + int lumpCount; + int cacheExtra; + PFNCACHE pfnCacheBuild; + int numpaths; + char **basedirs; + int *lumppathindices; +#ifndef SWDS + int tempWad; +#endif // SWDS +} cachewad_t; + +typedef struct mod_known_info_s +{ + qboolean shouldCRC; + qboolean firstCRCDone; + CRC32_t initialCRC; +} mod_known_info_t; + diff --git a/metamod/include/engine/modelgen.h b/metamod/include/engine/modelgen.h new file mode 100644 index 0000000..3d90bdd --- /dev/null +++ b/metamod/include/engine/modelgen.h @@ -0,0 +1,144 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MODELGEN_H +#define MODELGEN_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <67f6> ../engine/modelgen.h:37 */ +typedef enum synctype_e +{ + ST_SYNC = 0, + ST_RAND = 1, +} synctype_t; + +/* <4abae> ../engine/modelgen.h:40 */ +typedef enum aliasframetype_s +{ + ALIAS_SINGLE = 0, + ALIAS_GROUP = 1, +} aliasframetype_t; + +/* 203 */ +/* <4abce> ../engine/modelgen.h:42 */ +typedef enum aliasskintype_s +{ + ALIAS_SKIN_SINGLE = 0, + ALIAS_SKIN_GROUP = 1, +} aliasskintype_t; + +/* <4abee> ../engine/modelgen.h:44 */ +typedef struct mdl_s +{ + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; +} mdl_t; + +/* <4acd4> ../engine/modelgen.h:64 */ +typedef struct stvert_s +{ + int onseam; + int s; + int t; +} stvert_t; + +/* <4ad0e> ../engine/modelgen.h:70 */ +typedef struct dtriangle_s +{ + int facesfront; + int vertindex[3]; +} dtriangle_t; + +/* <4ad42> ../engine/modelgen.h:80 */ +typedef struct trivertx_s +{ + byte v[3]; + byte lightnormalindex; +} trivertx_t; + +/* <4ad80> ../engine/modelgen.h:85 */ +typedef struct daliasframe_s +{ + trivertx_t bboxmin, bboxmax; + char name[16]; +} daliasframe_t; + +/* <4adbe> ../engine/modelgen.h:91 */ +typedef struct daliasgroup_s +{ + int numframes; + trivertx_t bboxmin, bboxmax; +} daliasgroup_t; + +/* <4adfc> ../engine/modelgen.h:97 */ +typedef struct daliasskingroup_s +{ + int numskins; +} daliasskingroup_t; + +/* <4ae1e> ../engine/modelgen.h:101 */ +typedef struct daliasinterval_s +{ + float interval; +} daliasinterval_t; + +/* <4ae40> ../engine/modelgen.h:105 */ +typedef struct daliasskininterval_s +{ + float interval; +} daliasskininterval_t; + +/* <4ae62> ../engine/modelgen.h:109 */ +typedef struct daliasframetype_s +{ + aliasframetype_t type; +} daliasframetype_t; + +/* <4ae84> ../engine/modelgen.h:113 */ +typedef struct daliasskintype_s +{ + aliasskintype_t type; +} daliasskintype_t; + +#endif // MODELGEN_H diff --git a/metamod/include/engine/osconfig.h b/metamod/include/engine/osconfig.h new file mode 100644 index 0000000..bb45a62 --- /dev/null +++ b/metamod/include/engine/osconfig.h @@ -0,0 +1,194 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef _OSCONFIG_H +#define _OSCONFIG_H + +#ifdef _WIN32 // WINDOWS + #pragma warning(disable : 4005) +#endif // _WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _WIN32 // WINDOWS + #include + #include + #include // for support IPX + #define PSAPI_VERSION 1 + #include + #include + #include + #include + #include + #include +#else // _WIN32 + #include + #include + //#include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + // Deail with stupid macro in kernel.h + #undef __FUNCTION__ +#endif // _WIN32 + +#include +#include +#include +#include + +#include +#include + +#ifdef _WIN32 // WINDOWS + #define _CRT_SECURE_NO_WARNINGS + #define WIN32_LEAN_AND_MEAN + + #ifndef CDECL + #define CDECL __cdecl + #endif + #define STDCALL __stdcall + #define HIDDEN + #define NOINLINE __declspec(noinline) + #define ALIGN16 __declspec(align(16)) + #define FORCE_STACK_ALIGN + + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctlsocket(s, FIONBIO, (u_long*)&m) == 0); } + //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctlsocket(s, FIONREAD, (u_long*)&r); } + typedef int socklen_t; + #define SOCKET_FIONBIO(s, m) ioctlsocket(s, FIONBIO, (u_long*)&m) + #define SOCKET_MSGLEN(s, r) ioctlsocket(s, FIONREAD, (u_long*)&r) + #define SIN_GET_ADDR(saddr, r) r = (saddr)->S_un.S_addr + #define SIN_SET_ADDR(saddr, r) (saddr)->S_un.S_addr = (r) + #define SOCKET_CLOSE(s) closesocket(s) + #define SOCKET_AGAIN() (WSAGetLastError() == WSAEWOULDBLOCK) + + inline void* sys_allocmem(unsigned int size) { + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + } + + inline void sys_freemem(void* ptr, unsigned int size) { + VirtualFree(ptr, 0, MEM_RELEASE); + } +#else // _WIN32 + #ifdef __FUNCTION__ + #undef __FUNCTION__ + #endif + #define __FUNCTION__ __func__ + + #ifndef PAGESIZE + #define PAGESIZE 4096 + #endif + #define ALIGN(addr) (size_t)((size_t)addr & ~(PAGESIZE-1)) + #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + + #define _MAX_FNAME NAME_MAX + #define MAX_PATH 260 + + typedef void *HWND; + + typedef unsigned long DWORD; + typedef unsigned short WORD; + typedef unsigned int UNINT32; + + #define CDECL __attribute__ ((cdecl)) + #define STDCALL __attribute__ ((stdcall)) + #define HIDDEN __attribute__((visibility("hidden"))) + #define NOINLINE __attribute__((noinline)) + #define ALIGN16 __attribute__((aligned(16))) + #define FORCE_STACK_ALIGN __attribute__((force_align_arg_pointer)) + + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctl(s, FIONBIO, (int*)&m) == 0); } + //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctl(s, FIONREAD, (int*)&r); } + typedef int SOCKET; + #define INVALID_SOCKET (SOCKET)(~0) + #define SOCKET_FIONBIO(s, m) ioctl(s, FIONBIO, (char*)&m) + #define SOCKET_MSGLEN(s, r) ioctl(s, FIONREAD, (char*)&r) + #define SIN_GET_ADDR(saddr, r) r = (saddr)->s_addr + #define SIN_SET_ADDR(saddr, r) (saddr)->s_addr = (r) + #define SOCKET_CLOSE(s) close(s) + #define SOCKET_AGAIN() (errno == EAGAIN) + #define SOCKET_ERROR -1 + + inline void* sys_allocmem(unsigned int size) { + return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + inline void sys_freemem(void* ptr, unsigned int size) { + munmap(ptr, size); + } + + #define WSAENOPROTOOPT ENOPROTOOPT + + #ifndef FALSE + #define FALSE 0 + #endif + #ifndef TRUE + #define TRUE 1 + #endif +#endif // _WIN32 + +#ifdef _WIN32 + static const bool __isWindows = true; + static const bool __isLinux = false; +#else + static const bool __isWindows = false; + static const bool __isLinux = true; +#endif + +#define EXT_FUNC FORCE_STACK_ALIGN + +extern void __declspec(noreturn) rehlds_syserror(const char* fmt, ...); + +#endif // _OSCONFIG_H diff --git a/sdk/engine/progdefs.h b/metamod/include/engine/progdefs.h similarity index 97% rename from sdk/engine/progdefs.h rename to metamod/include/engine/progdefs.h index c7b9855..e27dc50 100644 --- a/sdk/engine/progdefs.h +++ b/metamod/include/engine/progdefs.h @@ -15,20 +15,18 @@ #ifndef PROGDEFS_H #define PROGDEFS_H #ifdef _WIN32 -#ifndef __MINGW32__ #pragma once -#endif /* not __MINGW32__ */ #endif -typedef struct +typedef struct globalvars_s { float time; float frametime; float force_retouch; string_t mapname; string_t startspot; - float deathmatch; - float coop; + float deathmatch_; + float coop_; float teamplay; float serverflags; float found_secrets; diff --git a/sdk/engine/progs.h b/metamod/include/engine/progs.h similarity index 100% rename from sdk/engine/progs.h rename to metamod/include/engine/progs.h diff --git a/metamod/include/engine/rehlds_api.h b/metamod/include/engine/rehlds_api.h new file mode 100644 index 0000000..3e7fb2a --- /dev/null +++ b/metamod/include/engine/rehlds_api.h @@ -0,0 +1,299 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "archtypes.h" +#include "cmd_rehlds.h" +#include "rehlds_interfaces.h" +#include "hookchains.h" +#include "FlightRecorder.h" +#include "interface.h" +#include "model.h" + +#define REHLDS_API_VERSION_MAJOR 2 +#define REHLDS_API_VERSION_MINOR 13 + +//Steam_NotifyClientConnect hook +typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_NotifyClientConnect; + +//SV_ConnectClient hook +typedef IVoidHookChain<> IRehldsHook_SV_ConnectClient; +typedef IVoidHookChainRegistry<> IRehldsHookRegistry_SV_ConnectClient; + +//SV_GetIDString hook +typedef IHookChain IRehldsHook_SV_GetIDString; +typedef IHookChainRegistry IRehldsHookRegistry_SV_GetIDString; + +//SV_SendServerinfo hook +typedef IVoidHookChain IRehldsHook_SV_SendServerinfo; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_SendServerinfo; + +//SV_CheckProtocol hook +typedef IHookChain IRehldsHook_SV_CheckProtocol; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckProtocol; + +//SVC_GetChallenge_mod hook +typedef IVoidHookChain IRehldsHook_SVC_GetChallenge_mod; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SVC_GetChallenge_mod; + +//SV_CheckKeyInfo hook +typedef IHookChain IRehldsHook_SV_CheckKeyInfo; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckKeyInfo; + +//SV_CheckIPRestrictions hook +typedef IHookChain IRehldsHook_SV_CheckIPRestrictions; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckIPRestrictions; + +//SV_FinishCertificateCheck hook +typedef IHookChain IRehldsHook_SV_FinishCertificateCheck; +typedef IHookChainRegistry IRehldsHookRegistry_SV_FinishCertificateCheck; + +//Steam_NotifyBotConnect hook +typedef IHookChain IRehldsHook_Steam_NotifyBotConnect; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_NotifyBotConnect; + +//SerializeSteamId +typedef IVoidHookChain IRehldsHook_SerializeSteamId; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SerializeSteamId; + +//SV_CompareUserID hook +typedef IHookChain IRehldsHook_SV_CompareUserID; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CompareUserID; + +//Steam_NotifyClientDisconnect +typedef IVoidHookChain IRehldsHook_Steam_NotifyClientDisconnect; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Steam_NotifyClientDisconnect; + +//PreProcessPacket +typedef IHookChain IRehldsHook_PreprocessPacket; +typedef IHookChainRegistry IRehldsHookRegistry_PreprocessPacket; + +//ValidateCommand +typedef IHookChain IRehldsHook_ValidateCommand; +typedef IHookChainRegistry IRehldsHookRegistry_ValidateCommand; + +//ExecuteServerStringCmd +typedef IVoidHookChain IRehldsHook_ExecuteServerStringCmd; +typedef IVoidHookChainRegistry IRehldsHookRegistry_ExecuteServerStringCmd; + +//ClientConnected +typedef IVoidHookChain IRehldsHook_ClientConnected; +typedef IVoidHookChainRegistry IRehldsHookRegistry_ClientConnected; + +//HandleNetCommand +typedef IVoidHookChain IRehldsHook_HandleNetCommand; +typedef IVoidHookChainRegistry IRehldsHookRegistry_HandleNetCommand; + +//Mod_LoadBrushModel +typedef IVoidHookChain IRehldsHook_Mod_LoadBrushModel; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Mod_LoadBrushModel; + +//Mod_LoadStudioModel +typedef IVoidHookChain IRehldsHook_Mod_LoadStudioModel; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Mod_LoadStudioModel; + +//SV_EmitEvents hook +typedef IVoidHookChain IRehldsHook_SV_EmitEvents; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_EmitEvents; + +//EV_PlayReliableEvent hook +typedef IVoidHookChain IRehldsHook_EV_PlayReliableEvent; +typedef IVoidHookChainRegistry IRehldsHookRegistry_EV_PlayReliableEvent; + +//SV_StartSound hook +typedef IVoidHookChain IRehldsHook_SV_StartSound; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_StartSound; + +//PF_Remove_I hook +typedef IVoidHookChain IRehldsHook_PF_Remove_I; +typedef IVoidHookChainRegistry IRehldsHookRegistry_PF_Remove_I; + +//PF_BuildSoundMsg_I hook +typedef IVoidHookChain IRehldsHook_PF_BuildSoundMsg_I; +typedef IVoidHookChainRegistry IRehldsHookRegistry_PF_BuildSoundMsg_I; + +//SV_WriteFullClientUpdate hook +typedef IVoidHookChain IRehldsHook_SV_WriteFullClientUpdate; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_WriteFullClientUpdate; + +//SV_CheckConsistencyResponse hook +typedef IHookChain IRehldsHook_SV_CheckConsistencyResponse; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckConsistencyResponse; + +//SV_DropClient hook +typedef IVoidHookChain IRehldsHook_SV_DropClient; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_DropClient; + +//SV_ActivateServer hook +typedef IVoidHookChain IRehldsHook_SV_ActivateServer; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_ActivateServer; + +//SV_WriteVoiceCodec hook +typedef IVoidHookChain IRehldsHook_SV_WriteVoiceCodec; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_WriteVoiceCodec; + +//Steam_GSGetSteamID hook +typedef IHookChain IRehldsHook_Steam_GSGetSteamID; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_GSGetSteamID; + +//SV_TransferConsistencyInfo hook +typedef IHookChain IRehldsHook_SV_TransferConsistencyInfo; +typedef IHookChainRegistry IRehldsHookRegistry_SV_TransferConsistencyInfo; + +//Steam_GSBUpdateUserData hook +typedef IHookChain IRehldsHook_Steam_GSBUpdateUserData; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_GSBUpdateUserData; + +//Cvar_DirectSet hook +typedef IVoidHookChain IRehldsHook_Cvar_DirectSet; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Cvar_DirectSet; + +//SV_EstablishTimeBase hook +typedef IVoidHookChain IRehldsHook_SV_EstablishTimeBase; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_EstablishTimeBase; + +//SV_Spawn_f hook +typedef IVoidHookChain<> IRehldsHook_SV_Spawn_f; +typedef IVoidHookChainRegistry<> IRehldsHookRegistry_SV_Spawn_f; + +//SV_CreatePacketEntities hook +typedef IHookChain IRehldsHook_SV_CreatePacketEntities; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CreatePacketEntities; + +//SV_EmitSound2 hook +typedef IHookChain IRehldsHook_SV_EmitSound2; +typedef IHookChainRegistry IRehldsHookRegistry_SV_EmitSound2; + +class IRehldsHookchains { +public: + virtual ~IRehldsHookchains() { } + + virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect() = 0; + virtual IRehldsHookRegistry_SV_ConnectClient* SV_ConnectClient() = 0; + virtual IRehldsHookRegistry_SV_GetIDString* SV_GetIDString() = 0; + virtual IRehldsHookRegistry_SV_SendServerinfo* SV_SendServerinfo() = 0; + virtual IRehldsHookRegistry_SV_CheckProtocol* SV_CheckProtocol() = 0; + virtual IRehldsHookRegistry_SVC_GetChallenge_mod* SVC_GetChallenge_mod() = 0; + virtual IRehldsHookRegistry_SV_CheckKeyInfo* SV_CheckKeyInfo() = 0; + virtual IRehldsHookRegistry_SV_CheckIPRestrictions* SV_CheckIPRestrictions() = 0; + virtual IRehldsHookRegistry_SV_FinishCertificateCheck* SV_FinishCertificateCheck() = 0; + virtual IRehldsHookRegistry_Steam_NotifyBotConnect* Steam_NotifyBotConnect() = 0; + virtual IRehldsHookRegistry_SerializeSteamId* SerializeSteamId() = 0; + virtual IRehldsHookRegistry_SV_CompareUserID* SV_CompareUserID() = 0; + virtual IRehldsHookRegistry_Steam_NotifyClientDisconnect* Steam_NotifyClientDisconnect() = 0; + virtual IRehldsHookRegistry_PreprocessPacket* PreprocessPacket() = 0; + virtual IRehldsHookRegistry_ValidateCommand* ValidateCommand() = 0; + virtual IRehldsHookRegistry_ClientConnected* ClientConnected() = 0; + virtual IRehldsHookRegistry_HandleNetCommand* HandleNetCommand() = 0; + virtual IRehldsHookRegistry_Mod_LoadBrushModel* Mod_LoadBrushModel() = 0; + virtual IRehldsHookRegistry_Mod_LoadStudioModel* Mod_LoadStudioModel() = 0; + virtual IRehldsHookRegistry_ExecuteServerStringCmd* ExecuteServerStringCmd() = 0; + virtual IRehldsHookRegistry_SV_EmitEvents* SV_EmitEvents() = 0; + virtual IRehldsHookRegistry_EV_PlayReliableEvent* EV_PlayReliableEvent() = 0; + virtual IRehldsHookRegistry_SV_StartSound* SV_StartSound() = 0; + virtual IRehldsHookRegistry_PF_Remove_I* PF_Remove_I() = 0; + virtual IRehldsHookRegistry_PF_BuildSoundMsg_I* PF_BuildSoundMsg_I() = 0; + virtual IRehldsHookRegistry_SV_WriteFullClientUpdate* SV_WriteFullClientUpdate() = 0; + virtual IRehldsHookRegistry_SV_CheckConsistencyResponse* SV_CheckConsistencyResponse() = 0; + virtual IRehldsHookRegistry_SV_DropClient* SV_DropClient() = 0; + virtual IRehldsHookRegistry_SV_ActivateServer* SV_ActivateServer() = 0; + virtual IRehldsHookRegistry_SV_WriteVoiceCodec* SV_WriteVoiceCodec() = 0; + virtual IRehldsHookRegistry_Steam_GSGetSteamID* Steam_GSGetSteamID() = 0; + virtual IRehldsHookRegistry_SV_TransferConsistencyInfo* SV_TransferConsistencyInfo() = 0; + virtual IRehldsHookRegistry_Steam_GSBUpdateUserData* Steam_GSBUpdateUserData() = 0; + virtual IRehldsHookRegistry_Cvar_DirectSet* Cvar_DirectSet() = 0; + virtual IRehldsHookRegistry_SV_EstablishTimeBase* SV_EstablishTimeBase() = 0; + virtual IRehldsHookRegistry_SV_Spawn_f* SV_Spawn_f() = 0; + virtual IRehldsHookRegistry_SV_CreatePacketEntities* SV_CreatePacketEntities() = 0; + virtual IRehldsHookRegistry_SV_EmitSound2* SV_EmitSound2() = 0; +}; + +struct RehldsFuncs_t { + void(*DropClient)(IGameClient* cl, bool crash, const char* fmt, ...); + void(*RejectConnection)(netadr_t *adr, char *fmt, ...); + qboolean(*SteamNotifyBotConnect)(IGameClient* cl); + sizebuf_t*(*GetNetMessage)(); + IGameClient*(*GetHostClient)(); + int*(*GetMsgReadCount)(); + qboolean(*FilterUser)(USERID_t*); + void(*NET_SendPacket)(unsigned int length, void *data, const netadr_t &to); + void(*TokenizeString)(char* s); + bool(*CheckChallenge)(const netadr_t& adr, int challenge); + void(*SendUserReg)(sizebuf_t* msg); + void(*WriteDeltaDescriptionsToClient)(sizebuf_t* msg); + void(*SetMoveVars)(); + void(*WriteMovevarsToClient)(sizebuf_t* msg); + char*(*GetClientFallback)(); + int*(*GetAllowCheats)(); + bool(*GSBSecure)(); + int(*GetBuildNumber)(); + double(*GetRealTime)(); + int*(*GetMsgBadRead)(); + cmd_source_t*(*GetCmdSource)(); + void(*Log)(const char* prefix, const char* msg); + DLL_FUNCTIONS *(*GetEntityInterface)(); + void(*EV_PlayReliableEvent)(IGameClient *cl, int entindex, short unsigned int eventindex, float delay, struct event_args_s *pargs); + int(*SV_LookupSoundIndex)(const char *sample); + void(*MSG_StartBitWriting)(sizebuf_t *buf); + void(*MSG_WriteBits)(uint32 data, int numbits); + void(*MSG_WriteBitVec3Coord)(const float *fa); + void(*MSG_EndBitWriting)(sizebuf_t *buf); + void*(*SZ_GetSpace)(sizebuf_t *buf, int length); + cvar_t*(*GetCvarVars)(); + int (*SV_GetChallenge)(const netadr_t& adr); + void (*SV_AddResource)(resourcetype_t type, const char *name, int size, unsigned char flags, int index); + int(*MSG_ReadShort)(void); + int(*MSG_ReadBuf)(int iSize, void *pbuf); + void(*MSG_WriteBuf)(sizebuf_t *sb, int iSize, void *buf); + void(*MSG_WriteByte)(sizebuf_t *sb, int c); + void(*MSG_WriteShort)(sizebuf_t *sb, int c); + void(*MSG_WriteString)(sizebuf_t *sb, const char *s); + void*(*GetPluginApi)(const char *name); + void(*RegisterPluginApi)(const char *name, void *impl); + qboolean(*SV_FileInConsistencyList)(const char *filename, struct consistency_s **ppconsist); + qboolean(*Steam_NotifyClientConnect)(IGameClient *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key); + void(*Steam_NotifyClientDisconnect)(IGameClient* cl); + void(*SV_StartSound)(int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int flags, int pitch); + bool(*SV_EmitSound2)(edict_t *entity, IGameClient *receiver, int channel, const char *sample, float volume, float attenuation, int flags, int pitch, int emitFlags, const float *pOrigin); + void (* SV_UpdateUserInfo)(IGameClient *pGameClient); +}; + +class IRehldsApi { +public: + virtual ~IRehldsApi() { } + + virtual int GetMajorVersion() = 0; + virtual int GetMinorVersion() = 0; + virtual const RehldsFuncs_t* GetFuncs() = 0; + virtual IRehldsHookchains* GetHookchains() = 0; + virtual IRehldsServerStatic* GetServerStatic() = 0; + virtual IRehldsServerData* GetServerData() = 0; + virtual IRehldsFlightRecorder* GetFlightRecorder() = 0; +}; + +#define VREHLDS_HLDS_API_VERSION "VREHLDS_HLDS_API_VERSION001" \ No newline at end of file diff --git a/metamod/include/engine/rehlds_interfaces.h b/metamod/include/engine/rehlds_interfaces.h new file mode 100644 index 0000000..e2b909f --- /dev/null +++ b/metamod/include/engine/rehlds_interfaces.h @@ -0,0 +1,132 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class INetChan; +class IGameClient; + +#include "archtypes.h" +#include "const.h" +#include "netadr.h" + +#include "common_rehlds.h" +#include "userid_rehlds.h" + +#ifdef REHLDS_SELF +#include "server.h" +#endif + +class INetChan; +class IGameClient; + +class IGameClient { +public: + virtual int GetId() = 0; + + virtual bool IsActive() = 0; + virtual void SetActive(bool active) = 0; + + virtual bool IsSpawned() = 0; + virtual void SetSpawned(bool spawned) = 0; + + virtual INetChan* GetNetChan() = 0; + + virtual sizebuf_t* GetDatagram() = 0; + + virtual edict_t* GetEdict() = 0; + + virtual USERID_t* GetNetworkUserID() = 0; + + virtual const char* GetName() = 0; + + virtual bool IsConnected() = 0; + virtual void SetConnected(bool connected) = 0; + + virtual uint32 GetVoiceStream(int stream_id) = 0; + virtual void SetLastVoiceTime(double time) = 0; + virtual double GetLastVoiceTime() = 0; + virtual bool GetLoopback() = 0; + virtual struct usercmd_s *GetLastCmd() = 0; + + // this must be the last virtual function in class +#ifdef REHLDS_SELF + virtual client_t* GetClient() = 0; +#endif +}; + +class INetChan { +public: + virtual const netadr_t* GetRemoteAdr() = 0; + virtual sizebuf_t* GetMessageBuf() = 0; + + + // this must be the last virtual function in class +#ifdef REHLDS_SELF + virtual netchan_t* GetChan() = 0; +#endif +}; + +#ifndef REHLDS_SELF +struct client_t; +#endif + +class IRehldsServerStatic { +public: + virtual ~IRehldsServerStatic() { } + + virtual int GetMaxClients() = 0; + virtual bool IsLogActive() = 0; + virtual IGameClient* GetClient(int id) = 0; + virtual client_t* GetClient_t(int id) = 0; + virtual int GetIndexOfClient_t(client_t* client) = 0; +}; + +class IRehldsServerData { +public: + virtual ~IRehldsServerData() { } + + virtual const char* GetModelName() = 0; + virtual const char* GetName() = 0; + virtual uint32 GetWorldmapCrc() = 0; + virtual uint8* GetClientDllMd5() = 0; + virtual sizebuf_t* GetDatagram() = 0; + virtual sizebuf_t* GetReliableDatagram() = 0; + + virtual void SetModelName(const char* modelname) = 0; + virtual void SetConsistencyNum(int num) = 0; + virtual int GetConsistencyNum() = 0; + virtual int GetResourcesNum() = 0; + virtual int GetDecalNameNum() = 0; + + virtual double GetTime() = 0; + virtual void SetResourcesNum(int num) = 0; + virtual struct resource_s *GetResource(int index) = 0; + virtual void SetName(const char* name) = 0; + virtual class ISteamGameServer *GetSteamGameServer() = 0; + virtual struct netadr_s *GetNetFrom() = 0; +}; diff --git a/sdk/engine/shake.h b/metamod/include/engine/shake.h similarity index 99% rename from sdk/engine/shake.h rename to metamod/include/engine/shake.h index 849c71a..1146a5e 100644 --- a/sdk/engine/shake.h +++ b/metamod/include/engine/shake.h @@ -33,6 +33,7 @@ extern void V_CalcShake( void ); extern int V_ScreenShake( const char *pszName, int iSize, void *pbuf ); extern int V_ScreenFade( const char *pszName, int iSize, void *pbuf ); + // Fade in/out extern int gmsgFade; diff --git a/metamod/include/engine/spritegn.h b/metamod/include/engine/spritegn.h new file mode 100644 index 0000000..96d8b03 --- /dev/null +++ b/metamod/include/engine/spritegn.h @@ -0,0 +1,90 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SPRITEGN_H +#define SPRITEGN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "modelgen.h" + + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') +#define SPRITE_VERSION 2 + + +typedef enum spriteframetype_e +{ + SPR_SINGLE = 0, + SPR_GROUP, + SPR_ANGLED +} spriteframetype_t; + +/* <4aea6> ../engine/spritegn.h:50 */ +typedef struct dsprite_s +{ + int ident; + int version; + int type; + int texFormat; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +/* <4af46> ../engine/spritegn.h:74 */ +typedef struct dspriteframe_s +{ + int origin[2]; + int width; + int height; +} dspriteframe_t; + +/* <4af84> ../engine/spritegn.h:80 */ +typedef struct dspritegroup_s +{ + int numframes; +} dspritegroup_t; + +/* <4afa6> ../engine/spritegn.h:84 */ +typedef struct dspriteinterval_s +{ + float interval; +} dspriteinterval_t; + +/* <4afe8> ../engine/spritegn.h:90 */ +typedef struct dspriteframetype_s +{ + spriteframetype_t type; +} dspriteframetype_t; + +#endif // SPRITEGN_H diff --git a/metamod/include/engine/static_map.h b/metamod/include/engine/static_map.h new file mode 100644 index 0000000..593cc39 --- /dev/null +++ b/metamod/include/engine/static_map.h @@ -0,0 +1,257 @@ +#pragma once + +#include "archtypes.h" +#include "crc32c.h" + +template +class CStaticMap { +protected: + virtual uint32 hash(const T_KEY& val) { + return crc32c((const unsigned char*)&val, sizeof(T_KEY)); + } + + virtual bool equals(const T_KEY& val1, const T_KEY& val2) { + return 0 == memcmp(&val1, &val2, sizeof(T_KEY)); + } + + struct map_node_t { + map_node_t* prev; + map_node_t* next; + T_KEY key; + T_VAL val; + }; + +private: + map_node_t* m_RootNodes[1 << ASSOC_2N]; + map_node_t m_AllNodes[MAX_VALS]; + map_node_t* m_FreeRoot; + + unsigned int GetRoodNodeId(const T_KEY& val) { return hash(val) & (0xFFFFFFFF >> (32 - ASSOC_2N)); } + + void unlink(map_node_t* node) { + map_node_t* prev = node->prev; + map_node_t* next = node->next; + + if (prev) { + prev->next = next; + } + + if (next) { + next->prev = prev; + } + + if (!prev) { + // this was a root node + unsigned int rootId = GetRoodNodeId(node->key); + if (m_RootNodes[rootId] != node) { + util_syserror("%s: invlid root node", __FUNCTION__); + return; + } + + m_RootNodes[rootId] = next; + } + } + + void link(map_node_t* node) { + unsigned int rootId = GetRoodNodeId(node->key); + map_node_t* root = m_RootNodes[rootId]; + node->prev = NULL; + node->next = root; + + if (root) { + root->prev = node; + } + + m_RootNodes[rootId] = node; + } + + void linkToFreeStack(map_node_t* node) { + node->next = m_FreeRoot; + if (m_FreeRoot) { + m_FreeRoot->prev = node; + } + m_FreeRoot = node; + } + +public: + CStaticMap() { + clear(); + } + + void clear() { + memset(m_RootNodes, 0, sizeof(m_RootNodes)); + memset(m_AllNodes, 0, sizeof(m_AllNodes)); + m_FreeRoot = NULL; + + for (int i = 0; i < MAX_VALS; i++) { + linkToFreeStack(&m_AllNodes[i]); + } + } + + map_node_t* get(const T_KEY& key) { + unsigned int rootId = GetRoodNodeId(key); + map_node_t* n = m_RootNodes[rootId]; + while (n) { + if (equals(n->key, key)) { + return n; + } + n = n->next; + } + return NULL; + } + + bool put(const T_KEY& key, T_VAL& val) { + map_node_t* n = get(key); + if (n) { + n->val = val; + return true; + } + + if (!m_FreeRoot) { + return false; + } + + n = m_FreeRoot; + m_FreeRoot = m_FreeRoot->next; + + n->key = key; + n->val = val; + + unsigned int rootId = GetRoodNodeId(key); + map_node_t* root = m_RootNodes[rootId]; + + if (root) { + root->prev = n; + } + + n->prev = NULL; + n->next = root; + m_RootNodes[rootId] = n; + + return true; + } + + void remove(map_node_t* node) { + unlink(node); + linkToFreeStack(node); + } + + bool remove(const T_KEY& key) { + map_node_t* n = get(key); + if (!n) { + return false; + } + + remove(n); + return true; + } + + class Iterator { + friend class CStaticMap; + protected: + CStaticMap* m_Map; + map_node_t** m_RootNodes; + unsigned int m_NextRootNode; + map_node_t* m_CurNode; + + void searchForNextNode() { + if (m_CurNode && m_CurNode->next) { + m_CurNode = m_CurNode->next; + return; + } + + m_CurNode = NULL; + while (!m_CurNode) { + if (m_NextRootNode >= (1 << ASSOC_2N)) { + return; + } + m_CurNode = m_RootNodes[m_NextRootNode++]; + } + } + + + Iterator(CStaticMap* m) { + m_Map = m; + m_RootNodes = m_Map->m_RootNodes; + m_NextRootNode = 0; + m_CurNode = NULL; + searchForNextNode(); + } + + public: + map_node_t* next() { + searchForNextNode(); + return m_CurNode; + } + + map_node_t* current() { + return m_CurNode; + } + + void remove() { + m_Map->remove(m_CurNode); + m_CurNode = NULL; + } + + bool hasElement() { + return m_CurNode != NULL; + } + }; + + Iterator iterator() { + return Iterator(this); + } +}; + +template +class CStringKeyStaticMap : public CStaticMap { +protected: + virtual uint32 hash(const char* const &val) { + return crc32c((const unsigned char*)val, strlen(val)); + } + + virtual bool equals(const char* const &val1, const char* const &val2) { + return !strcmp(val1, val2); + } + +public: + CStringKeyStaticMap() { + } + +}; + +template +class CICaseStringKeyStaticMap : public CStaticMap { +protected: + virtual uint32 hash(const char* const &val) { + uint32 cksum = 0; + const char* pcc = val; + if (cpuinfo.sse4_2) { + while (*pcc) { + char cc = *(pcc++); + if (cc >= 'A' || cc <= 'Z') { + cc |= 0x20; + } + cksum = crc32c_t8_sse(cksum, cc); + } + } else { + while (*pcc) { + char cc = *(pcc++); + if (cc >= 'A' || cc <= 'Z') { + cc |= 0x20; + } + cksum = crc32c_t8_nosse(cksum, cc); + } + } + return cksum; + } + + virtual bool equals(const char* const &val1, const char* const &val2) { + return !_stricmp(val1, val2); + } + +public: + CICaseStringKeyStaticMap() { + } + +}; diff --git a/sdk/engine/studio.h b/metamod/include/engine/studio.h similarity index 93% rename from sdk/engine/studio.h rename to metamod/include/engine/studio.h index c8a168b..1da691e 100644 --- a/sdk/engine/studio.h +++ b/metamod/include/engine/studio.h @@ -12,12 +12,7 @@ * without written permission from Valve LLC. * ****/ - - - - -#ifndef _STUDIO_H_ -#define _STUDIO_H_ +#pragma once /* ============================================================================== @@ -27,18 +22,18 @@ STUDIO MODELS Studio models are position independent, so the cache manager can move them. ============================================================================== */ - + #define MAXSTUDIOTRIANGLES 20000 // TODO: tune this #define MAXSTUDIOVERTS 2048 // TODO: tune this -#define MAXSTUDIOSEQUENCES 2048 // total animation sequences -- KSH incremented +#define MAXSTUDIOSEQUENCES 2048 // total animation sequences #define MAXSTUDIOSKINS 100 // total textures #define MAXSTUDIOSRCBONES 512 // bones allowed at source movement #define MAXSTUDIOBONES 128 // total bones actually used #define MAXSTUDIOMODELS 32 // sub-models per model #define MAXSTUDIOBODYPARTS 32 #define MAXSTUDIOGROUPS 16 -#define MAXSTUDIOANIMATIONS 2048 +#define MAXSTUDIOANIMATIONS 2048 // per sequence #define MAXSTUDIOMESHES 256 #define MAXSTUDIOEVENTS 1024 #define MAXSTUDIOPIVOTS 256 @@ -141,22 +136,12 @@ typedef struct vec3_t bbmax; } mstudiobbox_t; -#if !defined( CACHE_USER ) && !defined( QUAKEDEF_H ) -#define CACHE_USER -typedef struct cache_user_s -{ - void *data; -} cache_user_t; -#endif - -// // demand loaded sequence groups -// typedef struct { char label[32]; // textual name char name[64]; // file name - int32 unused1; // was "cache" - index pointer + int32 unused1; // was "cache" - index pointer int unused2; // was "data" - hack for group 0 } mstudioseqgroup_t; @@ -329,10 +314,10 @@ typedef struct #define STUDIO_NF_FLATSHADE 0x0001 #define STUDIO_NF_CHROME 0x0002 #define STUDIO_NF_FULLBRIGHT 0x0004 -#define STUDIO_NF_NOMIPS 0x0008 -#define STUDIO_NF_ALPHA 0x0010 -#define STUDIO_NF_ADDITIVE 0x0020 -#define STUDIO_NF_MASKED 0x0040 +#define STUDIO_NF_NOMIPS 0x0008 +#define STUDIO_NF_ALPHA 0x0010 +#define STUDIO_NF_ADDITIVE 0x0020 +#define STUDIO_NF_MASKED 0x0040 // motion flags #define STUDIO_X 0x0001 @@ -365,4 +350,9 @@ typedef struct #define RAD_TO_STUDIO (32768.0/M_PI) #define STUDIO_TO_RAD (M_PI/32768.0) -#endif + +#define STUDIO_NUM_HULLS 128 +#define STUDIO_NUM_PLANES (STUDIO_NUM_HULLS * 6) +#define STUDIO_CACHE_SIZE 16 + + diff --git a/metamod/include/engine/sys_shared.cpp b/metamod/include/engine/sys_shared.cpp new file mode 100644 index 0000000..a642c76 --- /dev/null +++ b/metamod/include/engine/sys_shared.cpp @@ -0,0 +1,72 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#include "sys_shared.h" + +#if defined(__GNUC__) +#include +#endif + +#define SSE3_FLAG (1<<0) +#define SSSE3_FLAG (1<<9) +#define SSE4_1_FLAG (1<<19) +#define SSE4_2_FLAG (1<<20) +#define POPCNT_FLAG (1<<23) +#define AVX_FLAG (1<<28) +#define AVX2_FLAG (1<<5) + +cpuinfo_t cpuinfo; + +void Sys_CheckCpuInstructionsSupport(void) +{ + unsigned int cpuid_data[4]; + +#if defined ASMLIB_H + cpuid_ex((int *)cpuid_data, 1, 0); +#elif defined(__GNUC__) + __get_cpuid(0x1, &cpuid_data[0], &cpuid_data[1], &cpuid_data[2], &cpuid_data[3]); +#else + __cpuidex((int *)cpuid_data, 1, 0); +#endif + + cpuinfo.sse3 = (cpuid_data[2] & SSE3_FLAG) ? 1 : 0; // ecx + cpuinfo.ssse3 = (cpuid_data[2] & SSSE3_FLAG) ? 1 : 0; + cpuinfo.sse4_1 = (cpuid_data[2] & SSE4_1_FLAG) ? 1 : 0; + cpuinfo.sse4_2 = (cpuid_data[2] & SSE4_2_FLAG) ? 1 : 0; + cpuinfo.popcnt = (cpuid_data[2] & POPCNT_FLAG) ? 1 : 0; + cpuinfo.avx = (cpuid_data[2] & AVX_FLAG) ? 1 : 0; + +#if defined ASMLIB_H + cpuid_ex((int *)cpuid_data, 7, 0); +#elif defined(__GNUC__) + __get_cpuid(0x7, &cpuid_data[0], &cpuid_data[1], &cpuid_data[2], &cpuid_data[3]); +#else + __cpuidex((int *)cpuid_data, 7, 0); +#endif + + cpuinfo.avx2 = (cpuid_data[1] & AVX2_FLAG) ? 1 : 0; // ebx +} \ No newline at end of file diff --git a/metamod/include/engine/sys_shared.h b/metamod/include/engine/sys_shared.h new file mode 100644 index 0000000..5b5da98 --- /dev/null +++ b/metamod/include/engine/sys_shared.h @@ -0,0 +1,39 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include + +typedef struct cpuinfo_s +{ + uint8 sse3, ssse3, sse4_1, sse4_2, avx, avx2, popcnt; +} cpuinfo_t; + +extern cpuinfo_t cpuinfo; + +void Sys_CheckCpuInstructionsSupport(void); diff --git a/metamod/include/engine/userid_rehlds.h b/metamod/include/engine/userid_rehlds.h new file mode 100644 index 0000000..ff73c5d --- /dev/null +++ b/metamod/include/engine/userid_rehlds.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "archtypes.h" + +// Authentication types +enum AUTH_IDTYPE +{ + AUTH_IDTYPE_UNKNOWN = 0, + AUTH_IDTYPE_STEAM = 1, + AUTH_IDTYPE_VALVE = 2, + AUTH_IDTYPE_LOCAL = 3 +}; + +/* <2e915> ../engine/userid.h:22 */ +typedef struct USERID_s +{ + int idtype; + uint64 m_SteamID; + unsigned int clientip; +} USERID_t; diff --git a/metamod/include/game_shared/GameEvent.h b/metamod/include/game_shared/GameEvent.h new file mode 100644 index 0000000..c585fff --- /dev/null +++ b/metamod/include/game_shared/GameEvent.h @@ -0,0 +1,138 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +enum GameEventType +{ + EVENT_INVALID = 0, + EVENT_WEAPON_FIRED, // tell bots the player is attack (argumens: 1 = attacker, 2 = NULL) + EVENT_WEAPON_FIRED_ON_EMPTY, // tell bots the player is attack without clip ammo (argumens: 1 = attacker, 2 = NULL) + EVENT_WEAPON_RELOADED, // tell bots the player is reloading his weapon (argumens: 1 = reloader, 2 = NULL) + + EVENT_HE_GRENADE_EXPLODED, // tell bots the HE grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL) + EVENT_FLASHBANG_GRENADE_EXPLODED, // tell bots the flashbang grenade is exploded (argumens: 1 = grenade thrower, 2 = explosion origin) + EVENT_SMOKE_GRENADE_EXPLODED, // tell bots the smoke grenade is exploded (argumens: 1 = grenade thrower, 2 = NULL) + EVENT_GRENADE_BOUNCED, + + EVENT_BEING_SHOT_AT, + EVENT_PLAYER_BLINDED_BY_FLASHBANG, // tell bots the player is flashed (argumens: 1 = flashed player, 2 = NULL) + EVENT_PLAYER_FOOTSTEP, // tell bots the player is running (argumens: 1 = runner, 2 = NULL) + EVENT_PLAYER_JUMPED, // tell bots the player is jumped (argumens: 1 = jumper, 2 = NULL) + EVENT_PLAYER_DIED, // tell bots the player is killed (argumens: 1 = victim, 2 = killer) + EVENT_PLAYER_LANDED_FROM_HEIGHT, // tell bots the player is fell with some damage (argumens: 1 = felled player, 2 = NULL) + EVENT_PLAYER_TOOK_DAMAGE, // tell bots the player is take damage (argumens: 1 = victim, 2 = attacker) + EVENT_HOSTAGE_DAMAGED, // tell bots the player has injured a hostage (argumens: 1 = hostage, 2 = injurer) + EVENT_HOSTAGE_KILLED, // tell bots the player has killed a hostage (argumens: 1 = hostage, 2 = killer) + + EVENT_DOOR, // tell bots the door is moving (argumens: 1 = door, 2 = NULL) + EVENT_BREAK_GLASS, // tell bots the glass has break (argumens: 1 = glass, 2 = NULL) + EVENT_BREAK_WOOD, // tell bots the wood has break (argumens: 1 = wood, 2 = NULL) + EVENT_BREAK_METAL, // tell bots the metal/computer has break (argumens: 1 = metal/computer, 2 = NULL) + EVENT_BREAK_FLESH, // tell bots the flesh has break (argumens: 1 = flesh, 2 = NULL) + EVENT_BREAK_CONCRETE, // tell bots the concrete has break (argumens: 1 = concrete, 2 = NULL) + + EVENT_BOMB_PLANTED, // tell bots the bomb has been planted (argumens: 1 = planter, 2 = NULL) + EVENT_BOMB_DROPPED, // tell bots the bomb has been dropped (argumens: 1 = NULL, 2 = NULL) + EVENT_BOMB_PICKED_UP, // let the bots hear the bomb pickup (argumens: 1 = player that pickup c4, 2 = NULL) + EVENT_BOMB_BEEP, // let the bots hear the bomb beeping (argumens: 1 = c4, 2 = NULL) + EVENT_BOMB_DEFUSING, // tell the bots someone has started defusing (argumens: 1 = defuser, 2 = NULL) + EVENT_BOMB_DEFUSE_ABORTED, // tell the bots someone has aborted defusing (argumens: 1 = NULL, 2 = NULL) + EVENT_BOMB_DEFUSED, // tell the bots the bomb is defused (argumens: 1 = defuser, 2 = NULL) + EVENT_BOMB_EXPLODED, // let the bots hear the bomb exploding (argumens: 1 = NULL, 2 = NULL) + + EVENT_HOSTAGE_USED, // tell bots the hostage is used (argumens: 1 = user, 2 = NULL) + EVENT_HOSTAGE_RESCUED, // tell bots the hostage is rescued (argumens: 1 = rescuer (CBasePlayer *), 2 = hostage (CHostage *)) + EVENT_ALL_HOSTAGES_RESCUED, // tell bots the all hostages are rescued (argumens: 1 = NULL, 2 = NULL) + + EVENT_VIP_ESCAPED, // tell bots the VIP is escaped (argumens: 1 = NULL, 2 = NULL) + EVENT_VIP_ASSASSINATED, // tell bots the VIP is assassinated (argumens: 1 = NULL, 2 = NULL) + EVENT_TERRORISTS_WIN, // tell bots the terrorists won the round (argumens: 1 = NULL, 2 = NULL) + EVENT_CTS_WIN, // tell bots the CTs won the round (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_DRAW, // tell bots the round was a draw (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_WIN, // tell carreer the round was a win (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_LOSS, // tell carreer the round was a loss (argumens: 1 = NULL, 2 = NULL) + EVENT_ROUND_START, // tell bots the round was started (when freeze period is expired) (argumens: 1 = NULL, 2 = NULL) + EVENT_PLAYER_SPAWNED, // tell bots the player is spawned (argumens: 1 = spawned player, 2 = NULL) + EVENT_CLIENT_CORPSE_SPAWNED, + EVENT_BUY_TIME_START, + EVENT_PLAYER_LEFT_BUY_ZONE, + EVENT_DEATH_CAMERA_START, + EVENT_KILL_ALL, + EVENT_ROUND_TIME, + EVENT_DIE, + EVENT_KILL, + EVENT_HEADSHOT, + EVENT_KILL_FLASHBANGED, + EVENT_TUTOR_BUY_MENU_OPENNED, + EVENT_TUTOR_AUTOBUY, + EVENT_PLAYER_BOUGHT_SOMETHING, + EVENT_TUTOR_NOT_BUYING_ANYTHING, + EVENT_TUTOR_NEED_TO_BUY_PRIMARY_WEAPON, + EVENT_TUTOR_NEED_TO_BUY_PRIMARY_AMMO, + EVENT_TUTOR_NEED_TO_BUY_SECONDARY_AMMO, + EVENT_TUTOR_NEED_TO_BUY_ARMOR, + EVENT_TUTOR_NEED_TO_BUY_DEFUSE_KIT, + EVENT_TUTOR_NEED_TO_BUY_GRENADE, + EVENT_CAREER_TASK_DONE, + + EVENT_START_RADIO_1, + EVENT_RADIO_COVER_ME, + EVENT_RADIO_YOU_TAKE_THE_POINT, + EVENT_RADIO_HOLD_THIS_POSITION, + EVENT_RADIO_REGROUP_TEAM, + EVENT_RADIO_FOLLOW_ME, + EVENT_RADIO_TAKING_FIRE, + EVENT_START_RADIO_2, + EVENT_RADIO_GO_GO_GO, + EVENT_RADIO_TEAM_FALL_BACK, + EVENT_RADIO_STICK_TOGETHER_TEAM, + EVENT_RADIO_GET_IN_POSITION_AND_WAIT, + EVENT_RADIO_STORM_THE_FRONT, + EVENT_RADIO_REPORT_IN_TEAM, + EVENT_START_RADIO_3, + EVENT_RADIO_AFFIRMATIVE, + EVENT_RADIO_ENEMY_SPOTTED, + EVENT_RADIO_NEED_BACKUP, + EVENT_RADIO_SECTOR_CLEAR, + EVENT_RADIO_IN_POSITION, + EVENT_RADIO_REPORTING_IN, + EVENT_RADIO_GET_OUT_OF_THERE, + EVENT_RADIO_NEGATIVE, + EVENT_RADIO_ENEMY_DOWN, + EVENT_END_RADIO, + + EVENT_NEW_MATCH, // tell bots the game is new (argumens: 1 = NULL, 2 = NULL) + EVENT_PLAYER_CHANGED_TEAM, // tell bots the player is switch his team (also called from ClientPutInServer()) (argumens: 1 = switcher, 2 = NULL) + EVENT_BULLET_IMPACT, // tell bots the player is shoot at wall (argumens: 1 = shooter, 2 = shoot trace end position) + EVENT_GAME_COMMENCE, // tell bots the game is commencing (argumens: 1 = NULL, 2 = NULL) + EVENT_WEAPON_ZOOMED, // tell bots the player is switch weapon zoom (argumens: 1 = zoom switcher, 2 = NULL) + EVENT_HOSTAGE_CALLED_FOR_HELP, // tell bots the hostage is talking (argumens: 1 = listener, 2 = NULL) + NUM_GAME_EVENTS, +}; + +extern const char *GameEventName[ NUM_GAME_EVENTS + 1 ]; diff --git a/metamod/include/game_shared/bitvec.h b/metamod/include/game_shared/bitvec.h new file mode 100644 index 0000000..f541bff --- /dev/null +++ b/metamod/include/game_shared/bitvec.h @@ -0,0 +1,157 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CBitVecAccessor { +public: + CBitVecAccessor(uint32 *pDWords, int iBit); + + void operator=(int val); + operator uint32(); + +private: + uint32 *m_pDWords; + int m_iBit; +}; + +// CBitVec allows you to store a list of bits and do operations on them like they were +// an atomic type +template +class CBitVec { +public: + CBitVec(); + + // Set all values to the specified value (0 or 1..) + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Operations on other bit vectors. + CBitVec &operator=(CBitVec const &other); + bool operator==(CBitVec const &other); + bool operator!=(CBitVec const &other); + + // Get underlying dword representations of the bits. + int GetNumDWords() { return NUM_DWORDS; } + uint32 GetDWord(int i); + void SetDWord(int i, uint32 val); + int GetNumBits(); + +private: + enum { NUM_DWORDS = NUM_BITS / 32 + !!(NUM_BITS & 31) }; + + unsigned int m_DWords[ NUM_DWORDS ]; +}; + +inline CBitVecAccessor::CBitVecAccessor(uint32 *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + +inline void CBitVecAccessor::operator=(int val) +{ + if (val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(uint32)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator uint32() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + +template +inline int CBitVec::GetNumBits() +{ + return NUM_BITS; +} + +template +inline CBitVec::CBitVec() +{ + for (int i = 0; i < NUM_DWORDS; ++i) + m_DWords[i] = 0; +} + +template +inline void CBitVec::Init(int val) +{ + for (int i = 0; i < GetNumBits(); ++i) + { + (*this)[i] = val; + } +} + +template +inline CBitVec &CBitVec::operator=(CBitVec const &other) +{ + Q_memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); + return *this; +} + +template +inline CBitVecAccessor CBitVec::operator[](int i) +{ + assert(i >= 0 && i < GetNumBits()); + return CBitVecAccessor(m_DWords, i); +} + +template +inline bool CBitVec::operator==(CBitVec const &other) +{ + for (int i = 0; i < NUM_DWORDS; ++i) + { + if (m_DWords[i] != other.m_DWords[i]) + return false; + } + + return true; +} + +template +inline bool CBitVec::operator!=(CBitVec const &other) +{ + return !(*this == other); +} + +template +inline uint32 CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + +template +inline void CBitVec::SetDWord(int i, uint32 val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} diff --git a/metamod/include/game_shared/bot/bot.h b/metamod/include/game_shared/bot/bot.h new file mode 100644 index 0000000..c391ec2 --- /dev/null +++ b/metamod/include/game_shared/bot/bot.h @@ -0,0 +1,164 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class BotProfile; + +// The base bot class from which bots for specific games are derived +class CBot: public CBasePlayer { +public: + virtual void Spawn() = 0; + + // invoked when injured by something + virtual BOOL TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) = 0; + + // invoked when killed + virtual void Killed(entvars_t *pevAttacker, int iGib) = 0; + virtual BOOL IsNetClient() = 0; + virtual void Think() = 0; + virtual BOOL IsBot() = 0; + virtual Vector GetAutoaimVector(float flDelta) = 0; + + // invoked when in contact with a CWeaponBox + virtual void OnTouchingWeapon(CWeaponBox *box) = 0; + virtual bool Initialize(const BotProfile *profile) = 0; + virtual void SpawnBot() = 0; + + // lightweight maintenance, invoked frequently + virtual void Upkeep() = 0; + + // heavyweight algorithms, invoked less often + virtual void Update() = 0; + + virtual void Run() = 0; + virtual void Walk() = 0; + virtual void Crouch() = 0; + virtual void StandUp() = 0; + virtual void MoveForward() = 0; + virtual void MoveBackward() = 0; + virtual void StrafeLeft() = 0; + virtual void StrafeRight() = 0; + + // returns true if jump was started + #define MUST_JUMP true + virtual bool Jump(bool mustJump = false) = 0; + + // zero any MoveForward(), Jump(), etc + virtual void ClearMovement() = 0; + + // Weapon interface + virtual void UseEnvironment() = 0; + virtual void PrimaryAttack() = 0; + virtual void ClearPrimaryAttack() = 0; + virtual void TogglePrimaryAttack() = 0; + virtual void SecondaryAttack() = 0; + virtual void Reload() = 0; + + // invoked when event occurs in the game (some events have NULL entities) + virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) = 0; + + // return true if we can see the point + virtual bool IsVisible(const Vector *pos, bool testFOV = false) const = 0; + + // return true if we can see any part of the player + virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const = 0; + + enum VisiblePartType:uint8 + { + NONE = 0x00, + CHEST = 0x01, + HEAD = 0x02, + LEFT_SIDE = 0x04, // the left side of the object from our point of view (not their left side) + RIGHT_SIDE = 0x08, // the right side of the object from our point of view (not their right side) + FEET = 0x10 + }; + + // if enemy is visible, return the part we see + virtual bool IsEnemyPartVisible(VisiblePartType part) const = 0; + + // return true if player is facing towards us + virtual bool IsPlayerFacingMe(CBasePlayer *other) const = 0; + + // returns true if other player is pointing right at us + virtual bool IsPlayerLookingAtMe(CBasePlayer *other) const = 0; + virtual void ExecuteCommand() = 0; + virtual void SetModel(const char *modelName) = 0; + +public: + unsigned int GetID() const { return m_id; } + bool IsRunning() const { return m_isRunning; } + bool IsCrouching() const { return m_isCrouching; } + + // return time last jump began + float GetJumpTimestamp() const { return m_jumpTimestamp; } + + // return our personality profile + const BotProfile *GetProfile() const { return m_profile; } + +public: + // the "personality" profile of this bot + const BotProfile *m_profile; + + // unique bot ID + unsigned int m_id; + + // Think mechanism variables + float m_flNextBotThink; + float m_flNextFullBotThink; + + // Command interface variables + float m_flPreviousCommandTime; + + // run/walk mode + bool m_isRunning; + + // true if crouching (ducking) + bool m_isCrouching; + float m_forwardSpeed; + float m_strafeSpeed; + float m_verticalSpeed; + + // bitfield of movement buttons + unsigned short m_buttonFlags; + + // time when we last began a jump + float m_jumpTimestamp; + + // the PostureContext represents the current settings of walking and crouching + struct PostureContext + { + bool isRunning; + bool isCrouching; + }; + + enum { MAX_POSTURE_STACK = 8 }; + PostureContext m_postureStack[MAX_POSTURE_STACK]; + + // index of top of stack + int m_postureStackIndex; +}; diff --git a/metamod/include/game_shared/bot/bot_constants.h b/metamod/include/game_shared/bot/bot_constants.h new file mode 100644 index 0000000..14438b5 --- /dev/null +++ b/metamod/include/game_shared/bot/bot_constants.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// We'll define our own version of this, because everyone else does. +// This needs to stay in sync with MAX_CLIENTS, but there's no header with the #define. +#define BOT_MAX_CLIENTS 32 + +// version number is MAJOR.MINOR +#define BOT_VERSION_MAJOR 1 +#define BOT_VERSION_MINOR 50 + +// Difficulty levels +enum BotDifficultyType +{ + BOT_EASY = 0, + BOT_NORMAL, + BOT_HARD, + BOT_EXPERT, + + NUM_DIFFICULTY_LEVELS +}; diff --git a/metamod/include/game_shared/bot/bot_manager.h b/metamod/include/game_shared/bot/bot_manager.h new file mode 100644 index 0000000..e232753 --- /dev/null +++ b/metamod/include/game_shared/bot/bot_manager.h @@ -0,0 +1,70 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// STL uses exceptions, but we are not compiling with them - ignore warning +#pragma warning(disable : 4530) + +#include + +class CNavArea; +class CGrenade; + +class ActiveGrenade { +public: + int m_id; + CGrenade *m_entity; + Vector m_detonationPosition; + float m_dieTimestamp; +}; + +typedef std::list ActiveGrenadeList; + +class CBotManager { +public: + virtual void ClientDisconnect(CBasePlayer *pPlayer) = 0; + virtual BOOL ClientCommand(CBasePlayer *pPlayer, const char *pcmd) = 0; + + virtual void ServerActivate() = 0; + virtual void ServerDeactivate() = 0; + + virtual void ServerCommand(const char *pcmd) = 0; + virtual void AddServerCommand(const char *cmd) = 0; + virtual void AddServerCommands() = 0; + + virtual void RestartRound() = 0; + virtual void StartFrame() = 0; + + // Events are propogated to all bots. + virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) = 0; // Invoked when event occurs in the game (some events have NULL entity). + virtual unsigned int GetPlayerPriority(CBasePlayer *player) const = 0; // return priority of player (0 = max pri) + +public: + // the list of active grenades the bots are aware of + ActiveGrenadeList m_activeGrenadeList; +}; diff --git a/metamod/include/game_shared/bot/bot_profile.h b/metamod/include/game_shared/bot/bot_profile.h new file mode 100644 index 0000000..5f000f5 --- /dev/null +++ b/metamod/include/game_shared/bot/bot_profile.h @@ -0,0 +1,116 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// long STL names get truncated in browse info. +#pragma warning(disable : 4786) + +#ifndef _WIN32 +#include +#include +#endif // _WIN32 + +#undef min +#undef max + +#include +#include + +#include "bot_constants.h" + +enum +{ + FirstCustomSkin = 100, + NumCustomSkins = 100, + LastCustomSkin = FirstCustomSkin + NumCustomSkins - 1, +}; + +enum BotProfileTeamType +{ + BOT_TEAM_T, + BOT_TEAM_CT, + BOT_TEAM_ANY +}; + +class BotProfile { +public: + const char *GetName() const { return m_name; } + float GetAggression() const { return m_aggression; } + float GetSkill() const { return m_skill; } + float GetTeamwork() const { return m_teamwork; } + int GetWeaponPreference(int i) const { return m_weaponPreference[i]; } + int GetWeaponPreferenceCount() const { return m_weaponPreferenceCount; } + int GetCost() const { return m_cost; } + int GetSkin() const { return m_skin; } + int GetVoicePitch() const { return m_voicePitch; } + float GetReactionTime() const { return m_reactionTime; } + float GetAttackDelay() const { return m_attackDelay; } + int GetVoiceBank() const { return m_voiceBank; } + bool PrefersSilencer() const { return m_prefersSilencer; } +public: + friend class BotProfileManager; + + char *m_name; + float m_aggression; + float m_skill; + float m_teamwork; + + enum { MAX_WEAPON_PREFS = 16 }; + + int m_weaponPreference[MAX_WEAPON_PREFS]; + int m_weaponPreferenceCount; + + int m_cost; + int m_skin; + + unsigned char m_difficultyFlags; + int m_voicePitch; + float m_reactionTime; + float m_attackDelay; + enum BotProfileTeamType m_teams; + bool m_prefersSilencer; + int m_voiceBank; +}; + +typedef std::list BotProfileList; + +class BotProfileManager { +public: + typedef std::vector VoiceBankList; + const BotProfileList *GetProfileList() const { return &m_profileList; } + const VoiceBankList *GetVoiceBanks() const { return &m_voiceBanks; } + +public: + BotProfileList m_profileList; + VoiceBankList m_voiceBanks; + + char *m_skins[NumCustomSkins]; + char *m_skinModelnames[NumCustomSkins]; + char *m_skinFilenames[NumCustomSkins]; + int m_nextSkin; +}; diff --git a/metamod/include/game_shared/bot/bot_util.h b/metamod/include/game_shared/bot/bot_util.h new file mode 100644 index 0000000..776d421 --- /dev/null +++ b/metamod/include/game_shared/bot/bot_util.h @@ -0,0 +1,141 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define COS_TABLE_SIZE 256 + +#define RAD_TO_DEG(deg) ((deg) * 180.0 / M_PI) +#define DEG_TO_RAD(rad) ((rad) * M_PI / 180.0) + +#define SIGN(num) (((num) < 0) ? -1 : 1) +#define ABS(num) (SIGN(num) * (num)) + +class CBasePlayer; +class BotProfile; + +enum PriorityType +{ + PRIORITY_LOW, PRIORITY_MEDIUM, PRIORITY_HIGH, PRIORITY_UNINTERRUPTABLE +}; + +// Simple class for tracking intervals of game time +class IntervalTimer { +public: + IntervalTimer() { m_timestamp = -1.0f; } + void Reset() { m_timestamp = gpGlobals->time; } + void Start() { m_timestamp = gpGlobals->time; } + void Invalidate() { m_timestamp = -1.0f; } + + bool HasStarted() const { return (m_timestamp > 0.0f); } + + // if not started, elapsed time is very large + float GetElapsedTime() const { return (HasStarted()) ? (gpGlobals->time - m_timestamp) : 99999.9f; } + bool IsLessThen(float duration) const { return (gpGlobals->time - m_timestamp < duration) ? true : false; } + bool IsGreaterThen(float duration) const { return (gpGlobals->time - m_timestamp > duration) ? true : false; } + +private: + float m_timestamp; +}; + +// Simple class for counting down a short interval of time +class CountdownTimer { +public: + CountdownTimer() { m_timestamp = -1.0f; m_duration = 0.0f; } + void Reset() { m_timestamp = gpGlobals->time + m_duration; } + + void Start(float duration) { m_timestamp = gpGlobals->time + duration; m_duration = duration; } + bool HasStarted() const { return (m_timestamp > 0.0f); } + + void Invalidate() { m_timestamp = -1.0f; } + bool IsElapsed() const { return (gpGlobals->time > m_timestamp); } + +private: + float m_duration; + float m_timestamp; +}; + +// Return true if the given entity is valid +inline bool IsEntityValid(CBaseEntity *entity) +{ + if (entity == NULL) + return false; + + if (FNullEnt(entity->pev)) + return false; + + if (FStrEq(STRING(entity->pev->netname), "")) + return false; + + if (entity->pev->flags & FL_DORMANT) + return false; + + return true; +} + +// Given two line segments: startA to endA, and startB to endB, return true if they intesect +// and put the intersection point in "result". +// Note that this computes the intersection of the 2D (x,y) projection of the line segments. +inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vector &startB, const Vector &endB, Vector *result = NULL) +{ + float denom = (endA.x - startA.x) * (endB.y - startB.y) - (endA.y - startA.y) * (endB.x - startB.x); + if (denom == 0.0f) + { + // parallel + return false; + } + + float numS = (startA.y - startB.y) * (endB.x - startB.x) - (startA.x - startB.x) * (endB.y - startB.y); + if (numS == 0.0f) + { + // coincident + return true; + } + + float numT = (startA.y - startB.y) * (endA.x - startA.x) - (startA.x - startB.x) * (endA.y - startA.y); + float s = numS / denom; + if (s < 0.0f || s > 1.0f) + { + // intersection is not within line segment of startA to endA + return false; + } + + float t = numT / denom; + if (t < 0.0f || t > 1.0f) + { + // intersection is not within line segment of startB to endB + return false; + } + + // compute intesection point + if (result != NULL) + { + *result = startA + s * (endA - startA); + } + + return true; +} diff --git a/metamod/include/game_shared/bot/improv.h b/metamod/include/game_shared/bot/improv.h new file mode 100644 index 0000000..e04d26d --- /dev/null +++ b/metamod/include/game_shared/bot/improv.h @@ -0,0 +1,120 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CBaseEntity; +class CNavLadder; + +// Improv-specific events +class IImprovEvent { +public: + virtual void OnMoveToSuccess(const Vector &goal) {}; // invoked when an improv reaches its MoveTo goal + + enum MoveToFailureType + { + FAIL_INVALID_PATH = 0, + FAIL_STUCK, + FAIL_FELL_OFF, + }; + + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) {} // invoked when an improv fails to reach a MoveTo goal + virtual void OnInjury(float amount) {} // invoked when the improv is injured +}; + +// The Improv interface definition +// An "Improv" is an improvisational actor that simulates the +// behavor of a human in an unscripted, "make it up as you go" manner. +class CImprov: public IImprovEvent { +public: + virtual ~CImprov() {} + virtual bool IsAlive() const = 0; // return true if this improv is alive + + virtual void MoveTo(const Vector &goal) = 0; // move improv towards far-away goal (pathfind) + virtual void LookAt(const Vector &target) = 0; // define desired view target + virtual void ClearLookAt() = 0; // remove view goal + virtual void FaceTo(const Vector &goal) = 0; // orient body towards goal + virtual void ClearFaceTo() = 0; // remove body orientation goal + + virtual bool IsAtMoveGoal(float error = 20.0f) const = 0; // return true if improv is standing on its movement goal + virtual bool HasLookAt() const = 0; // return true if improv has a look at goal + virtual bool HasFaceTo() const = 0; // return true if improv has a face to goal + virtual bool IsAtFaceGoal() const = 0; // return true if improv is facing towards its face goal + virtual bool IsFriendInTheWay(const Vector &goalPos) const = 0; // return true if a friend is blocking our line to the given goal position + virtual bool IsFriendInTheWay(CBaseEntity *myFriend, const Vector &goalPos) const = 0; // return true if the given friend is blocking our line to the given goal position + + virtual void MoveForward() = 0; + virtual void MoveBackward() = 0; + virtual void StrafeLeft() = 0; + virtual void StrafeRight() = 0; + virtual bool Jump() = 0; + virtual void Crouch() = 0; + virtual void StandUp() = 0; // "un-crouch" + + virtual void TrackPath(const Vector &pathGoal, float deltaT) = 0; // move along path by following "pathGoal" + virtual void StartLadder(const CNavLadder *ladder, enum NavTraverseType how, const Vector *approachPos, const Vector *departPos) = 0; // invoked when a ladder is encountered while following a path + + virtual bool TraverseLadder(const CNavLadder *ladder, enum NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT) = 0; // traverse given ladder + virtual bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal = NULL) = 0; // find "simple" ground height, treating current nav area as part of the floor + + virtual void Run() = 0; + virtual void Walk() = 0; + virtual void Stop() = 0; + + virtual float GetMoveAngle() const = 0; // return direction of movement + virtual float GetFaceAngle() const = 0; // return direction of view + + virtual const Vector &GetFeet() const = 0; // return position of "feet" - point below centroid of improv at feet level + virtual const Vector &GetCentroid() const = 0; + virtual const Vector &GetEyes() const = 0; + + virtual bool IsRunning() const = 0; + virtual bool IsWalking() const = 0; + virtual bool IsStopped() const = 0; + + virtual bool IsCrouching() const = 0; + virtual bool IsJumping() const = 0; + virtual bool IsUsingLadder() const = 0; + virtual bool IsOnGround() const = 0; + virtual bool IsMoving() const = 0; // if true, improv is walking, crawling, running somewhere + + virtual bool CanRun() const = 0; + virtual bool CanCrouch() const = 0; + virtual bool CanJump() const = 0; + virtual bool IsVisible(const Vector &pos, bool testFOV = false) const = 0; // return true if improv can see position + virtual bool IsPlayerLookingAtMe(CBasePlayer *other, float cosTolerance = 0.95f) const = 0; // return true if 'other' is looking right at me + virtual CBasePlayer *IsAnyPlayerLookingAtMe(int team = 0, float cosTolerance = 0.95f) const = 0; // return player on given team that is looking right at me (team == 0 means any team), NULL otherwise + + virtual CBasePlayer *GetClosestPlayerByTravelDistance(int team = 0, float *range = NULL) const = 0; // return actual travel distance to closest player on given team (team == 0 means any team) + virtual CNavArea *GetLastKnownArea() const = 0; + + virtual void OnUpdate(float deltaT) = 0; // a less frequent, full update 'tick' + virtual void OnUpkeep(float deltaT) = 0; // a frequent, lightweight update 'tick' + virtual void OnReset() = 0; // reset improv to initial state + virtual void OnGameEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other) = 0; // invoked when an event occurs in the game + virtual void OnTouch(CBaseEntity *other) = 0; // "other" has touched us +}; diff --git a/metamod/include/game_shared/bot/nav.h b/metamod/include/game_shared/bot/nav.h new file mode 100644 index 0000000..65d2721 --- /dev/null +++ b/metamod/include/game_shared/bot/nav.h @@ -0,0 +1,400 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// STL uses exceptions, but we are not compiling with them - ignore warning +#pragma warning(disable : 4530) + +// to help identify nav files +#define NAV_MAGIC_NUMBER 0xFEEDFACE + +// A place is a named group of navigation areas +typedef unsigned int Place; + +// ie: "no place" +#define UNDEFINED_PLACE 0 +#define ANY_PLACE 0xFFFF + +#define WALK_THRU_DOORS 0x01 +#define WALK_THRU_BREAKABLES 0x02 +#define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES) + +enum NavErrorType +{ + NAV_OK, + NAV_CANT_ACCESS_FILE, + NAV_INVALID_FILE, + NAV_BAD_FILE_VERSION, + NAV_CORRUPT_DATA, +}; + +enum NavAttributeType +{ + NAV_CROUCH = 0x01, // must crouch to use this node/area + NAV_JUMP = 0x02, // must jump to traverse this area + NAV_PRECISE = 0x04, // do not adjust for obstacles, just move along area + NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping +}; + +enum NavDirType +{ + NORTH = 0, + EAST, + SOUTH, + WEST, + + NUM_DIRECTIONS +}; + +// Defines possible ways to move from one area to another +enum NavTraverseType +{ + // NOTE: First 4 directions MUST match NavDirType + GO_NORTH = 0, + GO_EAST, + GO_SOUTH, + GO_WEST, + GO_LADDER_UP, + GO_LADDER_DOWN, + GO_JUMP, + + NUM_TRAVERSE_TYPES +}; + +enum NavCornerType +{ + NORTH_WEST = 0, + NORTH_EAST, + SOUTH_EAST, + SOUTH_WEST, + + NUM_CORNERS +}; + +enum NavRelativeDirType +{ + FORWARD = 0, + RIGHT, + BACKWARD, + LEFT, + UP, + DOWN, + + NUM_RELATIVE_DIRECTIONS +}; + +const float GenerationStepSize = 25.0f; // (30) was 20, but bots can't fit always fit +const float StepHeight = 18.0f; // if delta Z is greater than this, we have to jump to get up +const float JumpHeight = 41.8f; // if delta Z is less than this, we can jump up on it +const float JumpCrouchHeight = 58.0f; // (48) if delta Z is less than or equal to this, we can jumpcrouch up on it + +// Strictly speaking, you CAN get up a slope of 1.643 (about 59 degrees), but you move very, very slowly +// This slope will represent the slope you can navigate without much slowdown +// rise/run - if greater than this, we can't move up it (de_survivor canyon ramps) +const float MaxSlope = 1.4f; + +// instead of MaxSlope, we are using the following max Z component of a unit normal +const float MaxUnitZSlope = 0.7f; + +const float BotRadius = 10.0f; // circular extent that contains bot +const float DeathDrop = 200.0f; // (300) distance at which we will die if we fall - should be about 600, and pay attention to fall damage during pathfind + +const float HalfHumanWidth = 16.0f; +const float HalfHumanHeight = 36.0f; +const float HumanHeight = 72.0f; + +struct Extent +{ + Vector lo; + Vector hi; + + float SizeX() const { return hi.x - lo.x; } + float SizeY() const { return hi.y - lo.y; } + float SizeZ() const { return hi.z - lo.z; } + float Area() const { return SizeX() * SizeY(); } + + // return true if 'pos' is inside of this extent + bool Contains(const Vector *pos) const + { + return (pos->x >= lo.x && pos->x <= hi.x && + pos->y >= lo.y && pos->y <= hi.y && + pos->z >= lo.z && pos->z <= hi.z); + } +}; + +struct Ray +{ + Vector from; + Vector to; +}; + +inline NavDirType OppositeDirection(NavDirType dir) +{ + switch (dir) + { + case NORTH: + return SOUTH; + case EAST: + return WEST; + case SOUTH: + return NORTH; + case WEST: + return EAST; + } + + return NORTH; +} + +inline NavDirType DirectionLeft(NavDirType dir) +{ + switch (dir) + { + case NORTH: + return WEST; + case SOUTH: + return EAST; + case EAST: + return NORTH; + case WEST: + return SOUTH; + } + + return NORTH; +} + +inline NavDirType DirectionRight(NavDirType dir) +{ + switch (dir) + { + case NORTH: + return EAST; + case SOUTH: + return WEST; + case EAST: + return SOUTH; + case WEST: + return NORTH; + } + + return NORTH; +} + +inline void AddDirectionVector(Vector *v, NavDirType dir, float amount) +{ + switch (dir) + { + case NORTH: + v->y -= amount; + return; + case SOUTH: + v->y += amount; + return; + case EAST: + v->x += amount; + return; + case WEST: + v->x -= amount; + return; + } +} + +inline float DirectionToAngle(NavDirType dir) +{ + switch (dir) + { + case NORTH: + return 270.0f; + case EAST: + return 0.0f; + case SOUTH: + return 90.0f; + case WEST: + return 180.0f; + } + + return 0.0f; +} + +inline NavDirType AngleToDirection(float angle) +{ + while (angle < 0.0f) + angle += 360.0f; + + while (angle > 360.0f) + angle -= 360.0f; + + if (angle < 45 || angle > 315) + return EAST; + + if (angle >= 45 && angle < 135) + return SOUTH; + + if (angle >= 135 && angle < 225) + return WEST; + + return NORTH; +} + +inline void DirectionToVector2D(NavDirType dir, Vector2D *v) +{ + switch (dir) + { + case NORTH: + v->x = 0.0f; + v->y = -1.0f; + break; + case SOUTH: + v->x = 0.0f; + v->y = 1.0f; + break; + case EAST: + v->x = 1.0f; + v->y = 0.0f; + break; + case WEST: + v->x = -1.0f; + v->y = 0.0f; + break; + } +} + +inline void SnapToGrid(Vector *pos) +{ + int cx = pos->x / GenerationStepSize; + int cy = pos->y / GenerationStepSize; + pos->x = cx * GenerationStepSize; + pos->y = cy * GenerationStepSize; +} + +inline void SnapToGrid(float *value) +{ + int c = *value / GenerationStepSize; + *value = c * GenerationStepSize; +} + +// custom +inline float SnapToGrid(float value) +{ + int c = value / GenerationStepSize; + return c * GenerationStepSize; +} + +inline float NormalizeAngle(float angle) +{ + while (angle < -180.0f) + angle += 360.0f; + + while (angle > 180.0f) + angle -= 360.0f; + + return angle; +} + +inline float NormalizeAnglePositive(float angle) +{ + while (angle < 0.0f) + angle += 360.0f; + + while (angle >= 360.0f) + angle -= 360.0f; + + return angle; +} + +inline float AngleDifference(float a, float b) +{ + float angleDiff = a - b; + + while (angleDiff > 180.0f) + angleDiff -= 360.0f; + + while (angleDiff < -180.0f) + angleDiff += 360.0f; + + return angleDiff; +} + +inline bool AnglesAreEqual(float a, float b, float tolerance = 5.0f) +{ + if (abs(int64(AngleDifference(a, b))) < tolerance) + return true; + + return false; +} + +inline bool VectorsAreEqual(const Vector *a, const Vector *b, float tolerance = 0.1f) +{ + if (abs(a->x - b->x) < tolerance + && abs(a->y - b->y) < tolerance + && abs(a->z - b->z) < tolerance) + return true; + + return false; +} + +inline bool IsEntityWalkable(entvars_t *entity, unsigned int flags) +{ + // if we hit a door, assume its walkable because it will open when we touch it + if (FClassnameIs(entity, "func_door") || FClassnameIs(entity, "func_door_rotating")) + return (flags & WALK_THRU_DOORS) ? true : false; + + // if we hit a breakable object, assume its walkable because we will shoot it when we touch it + if (FClassnameIs(entity, "func_breakable") && entity->takedamage == DAMAGE_YES) + return (flags & WALK_THRU_BREAKABLES) ? true : false; + + return false; +} + +// Check LOS, ignoring any entities that we can walk through +inline bool IsWalkableTraceLineClear(Vector &from, Vector &to, unsigned int flags = 0) +{ + TraceResult result; + edict_t *ignore = NULL; + Vector useFrom = from; + + while (true) + { + UTIL_TraceLine(useFrom, to, ignore_monsters, ignore, &result); + + if (result.flFraction != 1.0f && IsEntityWalkable(VARS(result.pHit), flags)) + { + ignore = result.pHit; + + Vector dir = to - from; + dir.NormalizeInPlace(); + useFrom = result.vecEndPos + 5.0f * dir; + } + else + break; + } + + if (result.flFraction == 1.0f) + return true; + + return false; +} diff --git a/metamod/include/game_shared/bot/nav_area.h b/metamod/include/game_shared/bot/nav_area.h new file mode 100644 index 0000000..5c40b2a --- /dev/null +++ b/metamod/include/game_shared/bot/nav_area.h @@ -0,0 +1,320 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include + +class CNavArea; +enum NavEditCmdType +{ + EDIT_NONE, + EDIT_DELETE, // delete current area + EDIT_SPLIT, // split current area + EDIT_MERGE, // merge adjacent areas + EDIT_JOIN, // define connection between areas + EDIT_BREAK, // break connection between areas + EDIT_MARK, // mark an area for further operations + EDIT_ATTRIB_CROUCH, // toggle crouch attribute on current area + EDIT_ATTRIB_JUMP, // toggle jump attribute on current area + EDIT_ATTRIB_PRECISE, // toggle precise attribute on current area + EDIT_ATTRIB_NO_JUMP, // toggle inhibiting discontinuity jumping in current area + EDIT_BEGIN_AREA, // begin creating a new nav area + EDIT_END_AREA, // end creation of the new nav area + EDIT_CONNECT, // connect marked area to selected area + EDIT_DISCONNECT, // disconnect marked area from selected area + EDIT_SPLICE, // create new area in between marked and selected areas + EDIT_TOGGLE_PLACE_MODE, // switch between normal and place editing + EDIT_TOGGLE_PLACE_PAINTING, // switch between "painting" places onto areas + EDIT_PLACE_FLOODFILL, // floodfill areas out from current area + EDIT_PLACE_PICK, // "pick up" the place at the current area + EDIT_MARK_UNNAMED, // mark an unnamed area for further operations + EDIT_WARP_TO_MARK, // warp a spectating local player to the selected mark + EDIT_SELECT_CORNER, // select a corner on the current area + EDIT_RAISE_CORNER, // raise a corner on the current area + EDIT_LOWER_CORNER, // lower a corner on the current area +}; + +enum RouteType +{ + FASTEST_ROUTE, + SAFEST_ROUTE, +}; + +union NavConnect +{ + unsigned int id; + CNavArea *area; + + bool operator==(const NavConnect &other) const { return (area == other.area) ? true : false; } +}; + +typedef std::list NavConnectList; + +enum LadderDirectionType +{ + LADDER_UP = 0, + LADDER_DOWN, + NUM_LADDER_DIRECTIONS +}; + +class CNavLadder { +public: + Vector m_top; + Vector m_bottom; + float m_length; + NavDirType m_dir; + Vector2D m_dirVector; + CBaseEntity *m_entity; + + CNavArea *m_topForwardArea; + CNavArea *m_topLeftArea; + CNavArea *m_topRightArea; + CNavArea *m_topBehindArea; + CNavArea *m_bottomArea; + + bool m_isDangling; + + void OnDestroyNotify(CNavArea *dead) + { + if (dead == m_topForwardArea) + m_topForwardArea = NULL; + + if (dead == m_topLeftArea) + m_topLeftArea = NULL; + + if (dead == m_topRightArea) + m_topRightArea = NULL; + + if (dead == m_topBehindArea) + m_topBehindArea = NULL; + + if (dead == m_bottomArea) + m_bottomArea = NULL; + } +}; + +typedef std::list NavLadderList; + +class HidingSpot { +public: + enum + { + IN_COVER = 0x01, + GOOD_SNIPER_SPOT = 0x02, + IDEAL_SNIPER_SPOT = 0x04 + }; + + bool HasGoodCover() const { return (m_flags & IN_COVER) ? true : false; } + bool IsGoodSniperSpot() const { return (m_flags & GOOD_SNIPER_SPOT) ? true : false; } + bool IsIdealSniperSpot() const { return (m_flags & IDEAL_SNIPER_SPOT) ? true : false; } + + void SetFlags(unsigned char flags) { m_flags |= flags; } + unsigned char GetFlags() const { return m_flags; } + + const Vector *GetPosition() const { return &m_pos; } + unsigned int GetID() const { return m_id; } + +private: + Vector m_pos; + unsigned int m_id; + unsigned int m_marker; + unsigned char m_flags; +}; + +typedef std::list HidingSpotList; + +struct SpotOrder +{ + float t; + union + { + HidingSpot *spot; + unsigned int id; + }; +}; + +typedef std::list SpotOrderList; + +struct SpotEncounter +{ + NavConnect from; + NavDirType fromDir; + NavConnect to; + NavDirType toDir; + Ray path; // the path segment + SpotOrderList spotList; // list of spots to look at, in order of occurrence +}; + +typedef std::list SpotEncounterList; +typedef std::list NavAreaList; + +// A CNavArea is a rectangular region defining a walkable area in the map +class CNavArea { +public: + unsigned int GetID() const { return m_id; } + void SetAttributes(unsigned char bits) { m_attributeFlags = bits; } + unsigned char GetAttributes() const { return m_attributeFlags; } + void SetPlace(Place place) { m_place = place; } // set place descriptor + Place GetPlace() const { return m_place; } // get place descriptor + + int GetAdjacentCount(NavDirType dir) const { return m_connect[dir].size(); } // return number of connected areas in given direction + const NavConnectList *GetAdjacentList(NavDirType dir) const { return &m_connect[dir]; } + + const NavLadderList *GetLadderList(LadderDirectionType dir) const { return &m_ladder[dir]; } + + // for hunting algorithm + void SetClearedTimestamp(int teamID) { m_clearedTimestamp[teamID] = gpGlobals->time; } // set this area's "clear" timestamp to now + float GetClearedTimestamp(int teamID) { return m_clearedTimestamp[teamID]; } // get time this area was marked "clear" + + // hiding spots + const HidingSpotList *GetHidingSpotList() const { return &m_hidingSpotList; } + + float GetSizeX() const { return m_extent.hi.x - m_extent.lo.x; } + float GetSizeY() const { return m_extent.hi.y - m_extent.lo.y; } + + const Extent *GetExtent() const { return &m_extent; } + const Vector *GetCenter() const { return &m_center; } + + // approach areas + struct ApproachInfo + { + NavConnect here; // the approach area + NavConnect prev; // the area just before the approach area on the path + NavTraverseType prevToHereHow; + NavConnect next; // the area just after the approach area on the path + NavTraverseType hereToNextHow; + }; + + const ApproachInfo *GetApproachInfo(int i) const { return &m_approach[i]; } + int GetApproachInfoCount() const { return m_approachCount; } + + void SetParent(CNavArea *parent, NavTraverseType how = NUM_TRAVERSE_TYPES) { m_parent = parent; m_parentHow = how; } + CNavArea *GetParent() const { return m_parent; } + NavTraverseType GetParentHow() const { return m_parentHow; } + + void SetTotalCost(float value) { m_totalCost = value; } + float GetTotalCost() const { return m_totalCost; } + + void SetCostSoFar(float value) { m_costSoFar = value; } + float GetCostSoFar() const { return m_costSoFar; } + +public: + friend class CNavAreaGrid; + friend class CCSBotManager; + + unsigned int m_id; // unique area ID + Extent m_extent; // extents of area in world coords (NOTE: lo.z is not necessarily the minimum Z, but corresponds to Z at point (lo.x, lo.y), etc + Vector m_center; // centroid of area + unsigned char m_attributeFlags; // set of attribute bit flags (see NavAttributeType) + Place m_place; // place descriptor + + // height of the implicit corners + float m_neZ; + float m_swZ; + + enum { MAX_AREA_TEAMS = 2 }; + + // for hunting + float m_clearedTimestamp[MAX_AREA_TEAMS]; // time this area was last "cleared" of enemies + + // danger + float m_danger[MAX_AREA_TEAMS]; // danger of this area, allowing bots to avoid areas where they died in the past - zero is no danger + float m_dangerTimestamp[MAX_AREA_TEAMS]; // time when danger value was set - used for decaying + + // hiding spots + HidingSpotList m_hidingSpotList; + + // encounter spots + SpotEncounterList m_spotEncounterList; // list of possible ways to move thru this area, and the spots to look at as we do + + // approach areas + enum { MAX_APPROACH_AREAS = 16 }; + ApproachInfo m_approach[MAX_APPROACH_AREAS]; + unsigned char m_approachCount; + + // A* pathfinding algorithm + unsigned int m_marker; // used to flag the area as visited + CNavArea *m_parent; // the area just prior to this on in the search path + NavTraverseType m_parentHow; // how we get from parent to us + float m_totalCost; // the distance so far plus an estimate of the distance left + float m_costSoFar; // distance travelled so far + + CNavArea *m_nextOpen, *m_prevOpen; // only valid if m_openMarker == m_masterMarker + unsigned int m_openMarker; // if this equals the current marker value, we are on the open list + + // connections to adjacent areas + NavConnectList m_connect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction + NavLadderList m_ladder[ NUM_LADDER_DIRECTIONS ]; // list of ladders leading up and down from this area + + CNavNode *m_node[ NUM_CORNERS ]; // nav nodes at each corner of the area + NavAreaList m_overlapList; // list of areas that overlap this area + + CNavArea *m_prevHash, *m_nextHash; // for hash table in CNavAreaGrid +}; + +// The CNavAreaGrid is used to efficiently access navigation areas by world position +// Each cell of the grid contains a list of areas that overlap it +// Given a world position, the corresponding grid cell is ( x/cellsize, y/cellsize ) +class CNavAreaGrid { +public: + const float m_cellSize; + NavAreaList *m_grid; + int m_gridSizeX; + int m_gridSizeY; + float m_minX; + float m_minY; + unsigned int m_areaCount; // total number of nav areas + + enum { HASH_TABLE_SIZE = 256 }; + CNavArea *m_hashTable[HASH_TABLE_SIZE]; // hash table to optimize lookup by ID + inline int ComputeHashKey(unsigned int id) const // returns a hash key for the given nav area ID + { + return id & 0xFF; + } + inline int WorldToGridX(float wx) const + { + int x = (wx - m_minX) / m_cellSize; + if (x < 0) + x = 0; + + else if (x >= m_gridSizeX) + x = m_gridSizeX - 1; + + return x; + } + inline int WorldToGridY(float wy) const + { + int y = (wy - m_minY) / m_cellSize; + if (y < 0) + y = 0; + else if (y >= m_gridSizeY) + y = m_gridSizeY - 1; + + return y; + } +}; diff --git a/metamod/include/game_shared/bot/nav_node.h b/metamod/include/game_shared/bot/nav_node.h new file mode 100644 index 0000000..4c434a1 --- /dev/null +++ b/metamod/include/game_shared/bot/nav_node.h @@ -0,0 +1,110 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class CNavNode { +public: + // get navigation node connected in given direction, or NULL if cant go that way + CNavNode *GetConnectedNode(NavDirType dir) const; + const Vector *GetPosition() const; + const Vector *GetNormal() const { return &m_normal; } + unsigned int GetID() const { return m_id; } + + CNavNode *GetNext() { return m_next; } + + // create a connection FROM this node TO the given node, in the given direction + CNavNode *GetParent() const; + + void MarkAsVisited(NavDirType dir); // mark the given direction as having been visited + BOOL HasVisited(NavDirType dir); // return TRUE if the given direction has already been searched + + void Cover() { m_isCovered = true; } // TODO: Should pass in area that is covering + BOOL IsCovered() const { return m_isCovered; } // return true if this node has been covered by an area + + void AssignArea(CNavArea *area); // assign the given area to this node + CNavArea *GetArea() const; // return associated area + + void SetAttributes(unsigned char bits) { m_attributeFlags = bits; } + unsigned char GetAttributes() const { return m_attributeFlags; } + +public: + friend void DestroyNavigationMap(); + + Vector m_pos; // position of this node in the world + Vector m_normal; // surface normal at this location + CNavNode *m_to[ NUM_DIRECTIONS ]; // links to north, south, east, and west. NULL if no link + unsigned int m_id; // unique ID of this node + unsigned char m_attributeFlags; // set of attribute bit flags (see NavAttributeType) + + CNavNode *m_next; // next link in master list + + // below are only needed when generating + // flags for automatic node generation. If direction bit is clear, that direction hasn't been explored yet. + unsigned char m_visited; + CNavNode *m_parent; // the node prior to this in the search, which we pop back to when this node's search is done (a stack) + BOOL m_isCovered; // true when this node is "covered" by a CNavArea + CNavArea *m_area; // the area this node is contained within +}; + +inline CNavNode *CNavNode::GetConnectedNode(NavDirType dir) const +{ + return m_to[ dir ]; +} + +inline const Vector *CNavNode::GetPosition() const +{ + return &m_pos; +} + +inline CNavNode *CNavNode::GetParent() const +{ + return m_parent; +} + +inline void CNavNode::MarkAsVisited(NavDirType dir) +{ + m_visited |= (1 << dir); +} + +inline BOOL CNavNode::HasVisited(NavDirType dir) +{ + if (m_visited & (1 << dir)) + return true; + + return false; +} + +inline void CNavNode::AssignArea(CNavArea *area) +{ + m_area = area; +} + +inline CNavArea *CNavNode::GetArea() const +{ + return m_area; +} diff --git a/metamod/include/game_shared/bot/nav_path.h b/metamod/include/game_shared/bot/nav_path.h new file mode 100644 index 0000000..614aa06 --- /dev/null +++ b/metamod/include/game_shared/bot/nav_path.h @@ -0,0 +1,99 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// STL uses exceptions, but we are not compiling with them - ignore warning +#pragma warning(disable : 4530) + +class CNavPath { +public: + CNavPath() { m_segmentCount = 0; } + + struct PathSegment + { + CNavArea *area; // the area along the path + NavTraverseType how; // how to enter this area from the previous one + Vector pos; // our movement goal position at this point in the path + const CNavLadder *ladder; // if "how" refers to a ladder, this is it + }; + + const PathSegment *operator[](int i) { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; } + int GetSegmentCount() const { return m_segmentCount; } + const Vector &GetEndpoint() const { return m_path[ m_segmentCount - 1 ].pos; } + + bool IsValid() const { return (m_segmentCount > 0); } + void Invalidate() { m_segmentCount = 0; } +public: + enum { MAX_PATH_SEGMENTS = 256 }; + PathSegment m_path[ MAX_PATH_SEGMENTS ]; + int m_segmentCount; + + bool ComputePathPositions(); // determine actual path positions + bool BuildTrivialPath(const Vector *start, const Vector *goal); // utility function for when start and goal are in the same area + int FindNextOccludedNode(int anchor_); // used by Optimize() +}; + +// Monitor improv movement and determine if it becomes stuck +class CStuckMonitor { +public: + bool IsStuck() const { return m_isStuck; } + float GetDuration() const { return m_isStuck ? m_stuckTimer.GetElapsedTime() : 0.0f; } +public: + bool m_isStuck; // if true, we are stuck + Vector m_stuckSpot; // the location where we became stuck + IntervalTimer m_stuckTimer; // how long we have been stuck + + enum { MAX_VEL_SAMPLES = 5 }; + + float m_avgVel[ MAX_VEL_SAMPLES ]; + int m_avgVelIndex; + int m_avgVelCount; + Vector m_lastCentroid; + float m_lastTime; +}; + +// The CNavPathFollower class implements path following behavior +class CNavPathFollower { +public: + void SetImprov(CImprov *improv) { m_improv = improv; } + void SetPath(CNavPath *path) { m_path = path; } + + void Debug(bool status) { m_isDebug = status; } // turn debugging on/off +public: + int FindOurPositionOnPath(Vector *close, bool local) const; // return the closest point to our current position on current path + int FindPathPoint(float aheadRange, Vector *point, int *prevIndex); // compute a point a fixed distance ahead along our path. + + CImprov *m_improv; // who is doing the path following + CNavPath *m_path; // the path being followed + int m_segmentIndex; // the point on the path the improv is moving towards + int m_behindIndex; // index of the node on the path just behind us + Vector m_goal; // last computed follow goal + bool m_isLadderStarted; + bool m_isDebug; + CStuckMonitor m_stuckMonitor; +}; diff --git a/metamod/include/game_shared/bot/simple_state_machine.h b/metamod/include/game_shared/bot/simple_state_machine.h new file mode 100644 index 0000000..baa931e --- /dev/null +++ b/metamod/include/game_shared/bot/simple_state_machine.h @@ -0,0 +1,101 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +// Encapsulation of a finite-state-machine state +template +class SimpleState { +public: + SimpleState() { m_parent = NULL; } + + virtual ~SimpleState() {}; + virtual void OnEnter(T userData) {}; // when state is entered + virtual void OnUpdate(T userData) {}; // state behavior + virtual void OnExit(T userData) {}; // when state exited + virtual const char *GetName() const = 0; // return state name + + void SetParent(SimpleState *parent) + { + m_parent = parent; + } + SimpleState *GetParent() const + { + return m_parent; + } + +private: + // the parent state that contains this state + SimpleState *m_parent; +}; + +// Encapsulation of a finite state machine +template +class SimpleStateMachine { +public: + SimpleStateMachine() + { + m_state = NULL; + } + void Reset(T userData) + { + m_userData = userData; + m_state = NULL; + } + // change behavior state - WARNING: not re-entrant. Do not SetState() from within OnEnter() or OnExit() + void SetState(S *newState) + { + if (m_state) + m_state->OnExit(m_userData); + + newState->OnEnter(m_userData); + + m_state = newState; + m_stateTimer.Start(); + } + // how long have we been in the current state + float GetStateDuration() const + { + return m_stateTimer.GetElapsedTime(); + } + // return true if given state is current state of machine + bool IsState(const S *state) const + { + return (state == m_state); + } + // execute current state of machine + void Update() + { + if (m_state) + m_state->OnUpdate(m_userData); + } + +protected: + S *m_state; // current behavior state + IntervalTimer m_stateTimer; // how long have we been in the current state + T m_userData; +}; diff --git a/metamod/include/game_shared/perf_counter.h b/metamod/include/game_shared/perf_counter.h new file mode 100644 index 0000000..e99c700 --- /dev/null +++ b/metamod/include/game_shared/perf_counter.h @@ -0,0 +1,183 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#ifdef _WIN32 + #include + #include + #include +#else + #include + #include + #include + #include + #ifdef OSX + #include + #else + #include + #endif + #include +#endif + +#include +#include +#include +#include +#include + +class CPerformanceCounter +{ +public: + CPerformanceCounter(); + + void InitializePerformanceCounter(); + double GetCurTime(); + +private: + int m_iLowShift; + double m_flPerfCounterFreq; + double m_flCurrentTime; + double m_flLastCurrentTime; +}; + +inline CPerformanceCounter::CPerformanceCounter() : + m_iLowShift(0), + m_flPerfCounterFreq(0), + m_flCurrentTime(0), + m_flLastCurrentTime(0) +{ + InitializePerformanceCounter(); +} + +inline void CPerformanceCounter::InitializePerformanceCounter() +{ +#ifdef _WIN32 + + LARGE_INTEGER performanceFreq; + QueryPerformanceFrequency(&performanceFreq); + + // get 32 out of the 64 time bits such that we have around + // 1 microsecond resolution + unsigned int lowpart, highpart; + lowpart = (unsigned int)performanceFreq.LowPart; + highpart = (unsigned int)performanceFreq.HighPart; + m_iLowShift = 0; + + while (highpart || (lowpart > 2000000.0)) + { + m_iLowShift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + m_flPerfCounterFreq = 1.0 / (double)lowpart; + +#endif // _WIN32 +} + +inline double CPerformanceCounter::GetCurTime() +{ +#ifdef _WIN32 + + static int sametimecount; + static unsigned int oldtime; + static int first = 1; + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + QueryPerformanceCounter(&PerformanceCount); + if (m_iLowShift == 0) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + temp = ((unsigned int)PerformanceCount.LowPart >> m_iLowShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_iLowShift)); + } + + if (first) + { + oldtime = temp; + first = 0; + } + else + { + // check for turnover or backward time + if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) + { + // so we can't get stuck + oldtime = temp; + } + else + { + t2 = temp - oldtime; + + time = (double)t2 * m_flPerfCounterFreq; + oldtime = temp; + + m_flCurrentTime += time; + + if (m_flCurrentTime == m_flLastCurrentTime) + { + if (++sametimecount > 100000) + { + m_flCurrentTime += 1.0; + sametimecount = 0; + } + } + else + { + sametimecount = 0; + } + + m_flLastCurrentTime = m_flCurrentTime; + } + } + + return m_flCurrentTime; + +#else // _WIN32 + + struct timeval tp; + static int secbase = 0; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return (tp.tv_usec / 1000000.0); + } + + return ((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); + +#endif // _WIN32 +} diff --git a/metamod/include/game_shared/shared_util.h b/metamod/include/game_shared/shared_util.h new file mode 100644 index 0000000..c12156f --- /dev/null +++ b/metamod/include/game_shared/shared_util.h @@ -0,0 +1,63 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#ifndef _WIN32 +#include +#include +#endif + +// Simple utility function to allocate memory and duplicate a string +inline char *CloneString(const char *str) +{ + if (!str) + { + char *cloneStr = new char[1]; + cloneStr[0] = '\0'; + return cloneStr; + } + + char *cloneStr = new char [strlen(str) + 1]; + strcpy(cloneStr, str); + return cloneStr; +} + +// Simple utility function to allocate memory and duplicate a wide string +inline wchar_t *CloneWString(const wchar_t *str) +{ + if (!str) + { + wchar_t *cloneStr = new wchar_t[1]; + cloneStr[0] = L'\0'; + return cloneStr; + } + + wchar_t *cloneStr = new wchar_t [wcslen(str) + 1]; + wcscpy(cloneStr, str); + return cloneStr; +} diff --git a/metamod/include/game_shared/simple_checksum.h b/metamod/include/game_shared/simple_checksum.h new file mode 100644 index 0000000..236e765 --- /dev/null +++ b/metamod/include/game_shared/simple_checksum.h @@ -0,0 +1,49 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SIMPLE_CHECKSUM_H +#define SIMPLE_CHECKSUM_H +#ifdef _WIN32 +#pragma once +#endif + +// Compute a simple checksum for the given data. +// Each byte in the data is multiplied by its position to track re-ordering changes +inline unsigned int ComputeSimpleChecksum(const unsigned char *dataPointer, int dataLength) +{ + unsigned int checksum = 0; + for (int i = 1; i <= dataLength; i++) + { + checksum += (*dataPointer) * i; + ++dataPointer; + } + + return checksum; +} + +#endif // SIMPLE_CHECKSUM_H diff --git a/metamod/include/game_shared/steam_util.h b/metamod/include/game_shared/steam_util.h new file mode 100644 index 0000000..5431679 --- /dev/null +++ b/metamod/include/game_shared/steam_util.h @@ -0,0 +1,76 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class SteamFile +{ +public: + SteamFile(const char *filename); + ~SteamFile(); + + bool IsValid() const { return (m_fileData) ? true : false; } + bool Read(void *data, int length); + +private: + byte *m_fileData; + int m_fileDataLength; + + byte *m_cursor; + int m_bytesLeft; +}; + +inline SteamFile::SteamFile(const char *filename) +{ + m_fileData = (byte *)LOAD_FILE_FOR_ME(const_cast(filename), &m_fileDataLength); + m_cursor = m_fileData; + m_bytesLeft = m_fileDataLength; +} + +inline SteamFile::~SteamFile() +{ + if (m_fileData) + { + FREE_FILE(m_fileData); + m_fileData = NULL; + } +} + +inline bool SteamFile::Read(void *data, int length) +{ + if (length > m_bytesLeft || m_cursor == NULL || m_bytesLeft <= 0) + return false; + + byte *readCursor = static_cast(data); + for (int i = 0; i < length; ++i) + { + *readCursor++ = *m_cursor++; + --m_bytesLeft; + } + + return true; +} diff --git a/metamod/include/game_shared/voice_common.h b/metamod/include/game_shared/voice_common.h new file mode 100644 index 0000000..82dfb39 --- /dev/null +++ b/metamod/include/game_shared/voice_common.h @@ -0,0 +1,36 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "bitvec.h" + +// TODO: this should just be set to MAX_CLIENTS +#define VOICE_MAX_PLAYERS 32 +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec< VOICE_MAX_PLAYERS > CPlayerBitVec; diff --git a/metamod/include/game_shared/voice_gamemgr.h b/metamod/include/game_shared/voice_gamemgr.h new file mode 100644 index 0000000..851c93a --- /dev/null +++ b/metamod/include/game_shared/voice_gamemgr.h @@ -0,0 +1,56 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define UPDATE_INTERVAL 0.3 + +#include "voice_common.h" + +class CGameRules; +class CBasePlayer; + +class IVoiceGameMgrHelper { +public: + virtual ~IVoiceGameMgrHelper() = 0; + + // Called each frame to determine which players are allowed to hear each other. This overrides + // whatever squelch settings players have. + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) = 0; +}; + +// CVoiceGameMgr manages which clients can hear which other clients. +class CVoiceGameMgr { +public: + virtual ~CVoiceGameMgr() {}; +public: + int m_msgPlayerVoiceMask; + int m_msgRequestState; + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. +}; diff --git a/metamod/include/pm_shared/pm_defs.h b/metamod/include/pm_shared/pm_defs.h new file mode 100644 index 0000000..04bea26 --- /dev/null +++ b/metamod/include/pm_shared/pm_defs.h @@ -0,0 +1,192 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "pm_info.h" +#include "pmtrace.h" + +#ifndef USERCMD_H +#include "usercmd.h" +#endif + +#include "const.h" + +#define MAX_PHYSENTS 600 // Must have room for all entities in the world. +#define MAX_MOVEENTS 64 +#define MAX_CLIP_PLANES 5 + +#define PM_NORMAL 0x00000000 +#define PM_STUDIO_IGNORE 0x00000001 // Skip studio models +#define PM_STUDIO_BOX 0x00000002 // Use boxes for non-complex studio models (even in traceline) +#define PM_GLASS_IGNORE 0x00000004 // Ignore entities with non-normal rendermode +#define PM_WORLD_ONLY 0x00000008 // Only trace against the world + +#define PM_TRACELINE_PHYSENTSONLY 0 +#define PM_TRACELINE_ANYVISIBLE 1 + +typedef struct physent_s +{ + char name[32]; // Name of model, or "player" or "world". + int player; + vec3_t origin; // Model's origin in world coordinates. + struct model_s *model; // only for bsp models + struct model_s *studiomodel; // SOLID_BBOX, but studio clip intersections. + vec3_t mins, maxs; // only for non-bsp models + int info; // For client or server to use to identify (index into edicts or cl_entities) + vec3_t angles; // rotated entities need this info for hull testing to work. + + int solid; // Triggers and func_door type WATER brushes are SOLID_NOT + int skin; // BSP Contents for such things like fun_door water brushes. + int rendermode; // So we can ignore glass + + float frame; + int sequence; + byte controller[4]; + byte blending[2]; + + int movetype; + int takedamage; + int blooddecal; + int team; + int classnumber; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + +} physent_t; + +typedef struct playermove_s +{ + int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. + qboolean server; // For debugging, are we running physics code on server side? + qboolean multiplayer; // 1 == multiplayer server + float time; // realtime on host, for reckoning duck timing + float frametime; // Duration of this frame + vec3_t forward, right, up; // Vectors for angles + vec3_t origin; // Movement origin. + vec3_t angles; // Movement view angles. + vec3_t oldangles; // Angles before movement view angles were looked at. + vec3_t velocity; // Current movement direction. + vec3_t movedir; // For waterjumping, a forced forward velocity so we can fly over lip of ledge. + vec3_t basevelocity; // Velocity of the conveyor we are standing, e.g. + vec3_t view_ofs; // For ducking/dead + // Our eye position. + float flDuckTime; // Time we started duck + qboolean bInDuck; // In process of ducking or ducked already? + int flTimeStepSound; // For walking/falling + // Next time we can play a step sound + int iStepLeft; + float flFallVelocity; + vec3_t punchangle; + float flSwimTime; + float flNextPrimaryAttack; + int effects; // MUZZLE FLASH, e.g. + int flags; // FL_ONGROUND, FL_DUCKING, etc. + int usehull; // 0 = regular player hull, 1 = ducked player hull, 2 = point hull + float gravity; // Our current gravity and friction. + float friction; + int oldbuttons; // Buttons last usercmd + float waterjumptime; // Amount of time left in jumping out of water cycle. + qboolean dead; // Are we a dead player? + int deadflag; + int spectator; // Should we use spectator physics model? + int movetype; // Our movement type, NOCLIP, WALK, FLY + int onground; // -1 = in air, else pmove entity number + int waterlevel; + int watertype; + int oldwaterlevel; + char sztexturename[256]; + char chtexturetype; + float maxspeed; + float clientmaxspeed; + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + int numphysent; // world state + // Number of entities to clip against. + physent_t physents[MAX_PHYSENTS]; + int nummoveent; // Number of momvement entities (ladders) + physent_t moveents[MAX_MOVEENTS]; // just a list of ladders + int numvisent; // All things being rendered, for tracing against things you don't actually collide with + physent_t visents[MAX_PHYSENTS]; + usercmd_t cmd; // input to run through physics. + int numtouch; // Trace results for objects we collided with. + pmtrace_t touchindex[MAX_PHYSENTS]; + char physinfo[MAX_PHYSINFO_STRING]; // Physics info string + struct movevars_s *movevars; + vec_t _player_mins[4][3]; + vec_t _player_maxs[4][3]; + + const char *(*PM_Info_ValueForKey)(const char *s, const char *key); + void (*PM_Particle)(float *origin, int color, float life, int zpos, int zvel); + int (*PM_TestPlayerPosition)(float *pos, pmtrace_t *ptrace); + void (*Con_NPrintf)(int idx, char *fmt, ...); + void (*Con_DPrintf)(char *fmt, ...); + void (*Con_Printf)(char *fmt, ...); + double (*Sys_FloatTime)(); + void (*PM_StuckTouch)(int hitent, pmtrace_t *ptraceresult); + int (*PM_PointContents)(float *p, int *truecontents); + int (*PM_TruePointContents)(float *p); + int (*PM_HullPointContents)(struct hull_s *hull, int num, float *p); + pmtrace_t (*PM_PlayerTrace)(float *start, float *end, int traceFlags, int ignore_pe); + struct pmtrace_s *(*PM_TraceLine)(float *start, float *end, int flags, int usehulll, int ignore_pe); + int32 (*RandomLong)(int32 lLow, int32 lHigh); + float (*RandomFloat)(float flLow, float flHigh); + int (*PM_GetModelType)(struct model_s *mod); + void (*PM_GetModelBounds)(struct model_s *mod, float *mins, float *maxs); + void *(*PM_HullForBsp)(physent_t *pe, float *offset); + float (*PM_TraceModel)(physent_t *pEnt, float *start, float *end, trace_t *trace); + int (*COM_FileSize)(char *filename); + byte *(*COM_LoadFile)(char *path, int usehunk, int *pLength); + void (*COM_FreeFile)(void *buffer); + char *(*memfgets)(byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize); + qboolean runfuncs; + void (*PM_PlaySound)(int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); + const char *(*PM_TraceTexture)(int ground, float *vstart, float *vend); + void (*PM_PlaybackEventFull)(int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); + +} playermove_t; diff --git a/metamod/include/pm_shared/pm_info.h b/metamod/include/pm_shared/pm_info.h new file mode 100644 index 0000000..68375db --- /dev/null +++ b/metamod/include/pm_shared/pm_info.h @@ -0,0 +1,30 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define MAX_PHYSINFO_STRING 256 diff --git a/metamod/include/pm_shared/pm_materials.h b/metamod/include/pm_shared/pm_materials.h new file mode 100644 index 0000000..6468273 --- /dev/null +++ b/metamod/include/pm_shared/pm_materials.h @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define CTEXTURESMAX 1024 // max number of textures loaded +#define CBTEXTURENAMEMAX 17 // only load first n chars of name + +#define CHAR_TEX_CONCRETE 'C' // texture types +#define CHAR_TEX_METAL 'M' +#define CHAR_TEX_DIRT 'D' +#define CHAR_TEX_VENT 'V' +#define CHAR_TEX_GRATE 'G' +#define CHAR_TEX_TILE 'T' +#define CHAR_TEX_SLOSH 'S' +#define CHAR_TEX_WOOD 'W' +#define CHAR_TEX_COMPUTER 'P' +#define CHAR_TEX_GRASS 'X' +#define CHAR_TEX_GLASS 'Y' +#define CHAR_TEX_FLESH 'F' +#define CHAR_TEX_SNOW 'N' diff --git a/metamod/include/pm_shared/pm_movevars.h b/metamod/include/pm_shared/pm_movevars.h new file mode 100644 index 0000000..9d22d02 --- /dev/null +++ b/metamod/include/pm_shared/pm_movevars.h @@ -0,0 +1,59 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +typedef struct movevars_s +{ + float gravity; // Gravity for map + float stopspeed; // Deceleration when not moving + float maxspeed; // Max allowed speed + float spectatormaxspeed; + float accelerate; // Acceleration factor + float airaccelerate; // Same for when in open air + float wateraccelerate; // Same for when in water + float friction; + float edgefriction; // Extra friction near dropofs + float waterfriction; // Less in water + float entgravity; // 1.0 + float bounce; // Wall bounce value. 1.0 + float stepsize; // sv_stepsize; + float maxvelocity; // maximum server velocity. + float zmax; // Max z-buffer range (for GL) + float waveHeight; // Water wave height (for GL) + qboolean footsteps; // Play footstep sounds + char skyName[32]; // Name of the sky map + float rollangle; + float rollspeed; + float skycolor_r; // Sky color + float skycolor_g; + float skycolor_b; + float skyvec_x; // Sky vector + float skyvec_y; + float skyvec_z; + +} movevars_t; diff --git a/metamod/include/pm_shared/pm_shared.h b/metamod/include/pm_shared/pm_shared.h new file mode 100644 index 0000000..73a5371 --- /dev/null +++ b/metamod/include/pm_shared/pm_shared.h @@ -0,0 +1,75 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define PM_DEAD_VIEWHEIGHT -8 + +#define OBS_NONE 0 +#define OBS_CHASE_LOCKED 1 +#define OBS_CHASE_FREE 2 +#define OBS_ROAMING 3 +#define OBS_IN_EYE 4 +#define OBS_MAP_FREE 5 +#define OBS_MAP_CHASE 6 + +#define STEP_CONCRETE 0 +#define STEP_METAL 1 +#define STEP_DIRT 2 +#define STEP_VENT 3 +#define STEP_GRATE 4 +#define STEP_TILE 5 +#define STEP_SLOSH 6 +#define STEP_WADE 7 +#define STEP_LADDER 8 +#define STEP_SNOW 9 + +#define WJ_HEIGHT 8 +#define STOP_EPSILON 0.1 +#define MAX_CLIMB_SPEED 200 +#define PLAYER_DUCKING_MULTIPLIER 0.333 +#define PM_CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly. + +#define PLAYER_LONGJUMP_SPEED 350.0f // how fast we longjump + +// Ducking time +#define TIME_TO_DUCK 0.4 +#define STUCK_MOVEUP 1 + +#define PM_VEC_DUCK_HULL_MIN -18 +#define PM_VEC_HULL_MIN -36 +#define PM_VEC_DUCK_VIEW 12 +#define PM_VEC_VIEW 17 + +#define PM_PLAYER_MAX_SAFE_FALL_SPEED 580 // approx 20 feet +#define PM_PLAYER_MIN_BOUNCE_SPEED 350 +#define PM_PLAYER_FALL_PUNCH_THRESHHOLD 250 // won't punch player's screen/make scrape noise unless player falling at least this fast. + +// Only allow bunny jumping up to 1.2x server / player maxspeed setting +#define BUNNYJUMP_MAX_SPEED_FACTOR 1.2f + +extern struct playermove_s *pmove; diff --git a/metamod/include/public/FileSystem.h b/metamod/include/public/FileSystem.h new file mode 100644 index 0000000..e1ce53c --- /dev/null +++ b/metamod/include/public/FileSystem.h @@ -0,0 +1,189 @@ +//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include +#include + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +typedef FILE * FileHandle_t; +typedef int FileFindHandle_t; +typedef int WaitForResourcesHandle_t; + + +//----------------------------------------------------------------------------- +// Enums used by the interface +//----------------------------------------------------------------------------- +#ifndef FILESYSTEM_INTERNAL_H +typedef enum +{ + FILESYSTEM_SEEK_HEAD = 0, + FILESYSTEM_SEEK_CURRENT, + FILESYSTEM_SEEK_TAIL, +} FileSystemSeek_t; + +enum +{ + FILESYSTEM_INVALID_FIND_HANDLE = -1 +}; + +typedef enum +{ + // Don't print anything + FILESYSTEM_WARNING_QUIET = 0, + + // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUNCLOSED, + + // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTUSAGE, + + // Report all open/close events to console ( !slow! ) + FILESYSTEM_WARNING_REPORTALLACCESSES +} FileWarningLevel_t; + +#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 +#endif + +// turn off any windows defines +#undef GetCurrentDirectory + +//----------------------------------------------------------------------------- +// Purpose: Main file system interface +//----------------------------------------------------------------------------- +class IFileSystem : public IBaseInterface +{ +public: + // Mount and unmount the filesystem + virtual void Mount( void ) = 0; + virtual void Unmount( void ) = 0; + + // Remove all search paths (including write path?) + virtual void RemoveAllSearchPaths( void ) = 0; + + // Add paths in priority order (mod dir, game dir, ....) + // If one or more .pak files are in the specified directory, then they are + // added after the file system path + // If the path is the relative path to a .bsp file, then any previous .bsp file + // override is cleared and the current .bsp is searched for an embedded PAK file + // and this file becomes the highest priority search path ( i.e., it's looked at first + // even before the mod's file system path ). + virtual void AddSearchPath( const char *pPath, const char *pathID ) = 0; + virtual bool RemoveSearchPath( const char *pPath ) = 0; + + // Deletes a file + virtual void RemoveFile( const char *pRelativePath, const char *pathID ) = 0; + + // this isn't implementable on STEAM as is. + virtual void CreateDirHierarchy( const char *path, const char *pathID ) = 0; + + // File I/O and info + virtual bool FileExists( const char *pFileName ) = 0; + virtual bool IsDirectory( const char *pFileName ) = 0; + + // opens a file + // if pathID is NULL, all paths will be searched for the file + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; + + virtual void Close( FileHandle_t file ) = 0; + + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; + virtual unsigned int Tell( FileHandle_t file ) = 0; + + virtual unsigned int Size( FileHandle_t file ) = 0; + virtual unsigned int Size( const char *pFileName ) = 0; + + virtual long GetFileTime( const char *pFileName ) = 0; + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; + + virtual bool IsOk( FileHandle_t file ) = 0; + + virtual void Flush( FileHandle_t file ) = 0; + virtual bool EndOfFile( FileHandle_t file ) = 0; + + virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; + virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; + virtual int FPrintf( FileHandle_t file, char *pFormat, ... ) = 0; + + // direct filesystem buffer access + // returns a handle to a buffer containing the file data + // this is the optimal way to access the complete data for a file, + // since the file preloader has probably already got it in memory + virtual void *GetReadBuffer( FileHandle_t file, int *outBufferSize, bool failIfNotInCache ) = 0; + virtual void ReleaseReadBuffer( FileHandle_t file, void *readBuffer ) = 0; + + // FindFirst/FindNext + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID = 0L ) = 0; + virtual const char *FindNext( FileFindHandle_t handle ) = 0; + virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; + virtual void FindClose( FileFindHandle_t handle ) = 0; + + virtual void GetLocalCopy( const char *pFileName ) = 0; + + virtual const char *GetLocalPath( const char *pFileName, char *pLocalPath, int localPathBufferSize ) = 0; + + // Note: This is sort of a secondary feature; but it's really useful to have it here + virtual char *ParseFile( char* pFileBytes, char* pToken, bool* pWasQuoted ) = 0; + + // Returns true on success ( based on current list of search paths, otherwise false if it can't be resolved ) + virtual bool FullPathToRelativePath( const char *pFullpath, char *pRelative ) = 0; + + // Gets the current working directory + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; + + // Dump to printf/OutputDebugString the list of files that have not been closed + virtual void PrintOpenedFiles( void ) = 0; + + virtual void SetWarningFunc( void (*pfnWarning)( const char *fmt, ... ) ) = 0; + virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; + + virtual void LogLevelLoadStarted( const char *name ) = 0; + virtual void LogLevelLoadFinished( const char *name ) = 0; + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; + virtual int PauseResourcePreloading( void ) = 0; + virtual int ResumeResourcePreloading( void ) = 0; + virtual int SetVBuf( FileHandle_t stream, char *buffer, int mode, long size ) = 0; + virtual void GetInterfaceVersion( char *p, int maxlen ) = 0; + virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; + + // starts waiting for resources to be available + // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; + // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done + // returns false if no progress is available + // any calls after complete is true or on an invalid handle will return false, 0.0f, true + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; + // cancels a progress call + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; + // returns true if the appID has all its caches fully preloaded + virtual bool IsAppReadyForOfflinePlay( int appID ) = 0; + + // interface for custom pack files > 4Gb + virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; + + // open a file but force the data to come from the steam cache, NOT from disk + virtual FileHandle_t OpenFromCacheForRead( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; + + virtual void AddSearchPathNoWrite( const char *pPath, const char *pathID ) = 0; +}; + +// Steam3/Src compat +#define IBaseFileSystem IFileSystem + +#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" + +#endif // FILESYSTEM_H diff --git a/metamod/include/public/basetypes.h b/metamod/include/public/basetypes.h new file mode 100644 index 0000000..a953ffe --- /dev/null +++ b/metamod/include/public/basetypes.h @@ -0,0 +1,287 @@ +//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BASETYPES_H +#define BASETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "protected_things.h" +#include "commonmacros.h" + + +// For backward compatibilty only... +#include "tier0/platform.h" + +// stdio.h +#ifndef NULL +#define NULL 0 +#endif + + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + x; \ + ++__executeCount; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +#ifndef MATHLIB_H +// In case this ever changes +#define M_PI 3.14159265358979323846 + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif // MATHLIB_H + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + + +typedef int BOOL; +typedef int qboolean; +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short word; + +typedef float vec_t; + + +// FIXME: this should move +#ifndef __cplusplus +#define true TRUE +#define false FALSE +#endif + +//----------------------------------------------------------------------------- +// look for NANs, infinities, and underflows. +// This assumes the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- + +#ifdef __cplusplus + +inline unsigned long& FloatBits(vec_t& f) +{ + return *reinterpret_cast(&f); +} + +inline unsigned long const& FloatBits(vec_t const& f) +{ + return *reinterpret_cast(&f); +} + +inline vec_t BitsToFloat(unsigned long i) +{ + return *reinterpret_cast(&i); +} + +inline bool IsFinite(vec_t f) +{ + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +} + +inline unsigned long FloatAbsBits(vec_t f) +{ + return FloatBits(f) & 0x7FFFFFFF; +} + +inline float FloatMakeNegative(vec_t f) +{ + return BitsToFloat(FloatBits(f) | 0x80000000); +} + +#if defined( WIN32 ) + +//#include +// Just use prototype from math.h +#ifdef __cplusplus +extern "C" +{ +#endif + double __cdecl fabs(double); +#ifdef __cplusplus +} +#endif + +// In win32 try to use the intrinsic fabs so the optimizer can do it's thing inline in the code +#pragma intrinsic( fabs ) +// Also, alias float make positive to use fabs, too +// NOTE: Is there a perf issue with double<->float conversion? +inline float FloatMakePositive(vec_t f) +{ + return fabs(f); +} +#else +inline float FloatMakePositive(vec_t f) +{ + return BitsToFloat(FloatBits(f) & 0x7FFFFFFF); +} +#endif + +inline float FloatNegate(vec_t f) +{ + return BitsToFloat(FloatBits(f) ^ 0x80000000); +} + + +#define FLOAT32_NAN_BITS (unsigned long)0x7FC00000 // not a number! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + +#endif + +// FIXME: why are these here? Hardly anyone actually needs them. +struct valve_color24 +{ + byte r, g, b; +}; + +typedef struct valve_color32_s +{ + bool operator!=(const struct valve_color32_s &other) const; + + byte r, g, b, a; +} valve_color32; + +inline bool valve_color32::operator!=(const valve_color32 &other) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct valve_colorRGBExp32 +{ + byte r, g, b; + signed char exponent; +}; + +struct valve_colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef UNUSED +#define UNUSED(x) (x = x) // for pesky compiler / lint warnings +#endif + +#ifdef __cplusplus + +struct vrect_t +{ + int x, y, width, height; + vrect_t *pnext; +}; + +#endif + + +//----------------------------------------------------------------------------- +// MaterialRect_t struct - used for DrawDebugText +//----------------------------------------------------------------------------- +struct Rect_t +{ + int x, y; + int width, height; +}; + + +//----------------------------------------------------------------------------- +// Declares a type-safe handle type; you can't assign one handle to the next +//----------------------------------------------------------------------------- + +// 32-bit pointer handles. + +// Typesafe 8-bit and 16-bit handles. +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==(const CBaseIntHandle &other) { return m_Handle == other.m_Handle; } + inline bool operator!=(const CBaseIntHandle &other) { return m_Handle != other.m_Handle; } + + // Only the code that doles out these handles should use these functions. + // Everyone else should treat them as a transparent type. + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue(HandleType val) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle < unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle16(val); + } + +protected: + inline CIntHandle16(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle < unsigned long > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle32(val); + } + +protected: + inline CIntHandle32(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +// NOTE: This macro is the same as windows uses; so don't change the guts of it +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +#endif // BASETYPES_H diff --git a/metamod/include/public/commonmacros.h b/metamod/include/public/commonmacros.h new file mode 100644 index 0000000..6bc9675 --- /dev/null +++ b/metamod/include/public/commonmacros.h @@ -0,0 +1,30 @@ +#ifndef COMMONMACROS_H +#define COMMONMACROS_H +#pragma once + + +// ------------------------------------------------------- +// +// commonmacros.h +// +// This should contain ONLY general purpose macros that are +// appropriate for use in engine/launcher/all tools +// +// ------------------------------------------------------- + +#include "osconfig.h" +// Makes a 4-byte "packed ID" int out of 4 characters +#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) ) + +// Compares a string with a 4-byte packed ID constant +#define STRING_MATCHES_ID( p, id ) ( (*((int *)(p)) == (id) ) ? true : false ) +#define ID_TO_STRING( id, p ) ( (p)[3] = (((id)>>24) & 0xFF), (p)[2] = (((id)>>16) & 0xFF), (p)[1] = (((id)>>8) & 0xFF), (p)[0] = (((id)>>0) & 0xFF) ) + +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +// Keeps clutter down a bit, when using a float as a bit-vector +#define SETBITS(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) +#define CLEARBITS(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) +#define FBitSet(flBitVector, bit) ((flBitVector) & (bit)) + +#endif // COMMONMACROS_H diff --git a/metamod/include/public/interface.cpp b/metamod/include/public/interface.cpp new file mode 100644 index 0000000..9a12eef --- /dev/null +++ b/metamod/include/public/interface.cpp @@ -0,0 +1,263 @@ +#include "precompiled.h" +#include "interface.h" + +#if !defined ( _WIN32 ) +// Linux doesn't have this function so this emulates its functionality +// +// +void *GetModuleHandle(const char *name) +{ + void *handle; + + if (name == NULL) + { + // hmm, how can this be handled under linux.... + // is it even needed? + return NULL; + } + + if ((handle=dlopen(name, RTLD_NOW)) == NULL) + { + //printf("Error:%s\n",dlerror()); + // couldn't open this file + return NULL; + } + + // read "man dlopen" for details + // in short dlopen() inc a ref count + // so dec the ref count by performing the close + dlclose(handle); + return handle; +} +#endif + +// ------------------------------------------------------------------------------------ // +// InterfaceReg. +// ------------------------------------------------------------------------------------ // +InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; + + +InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + + + +// ------------------------------------------------------------------------------------ // +// CreateInterface. +// ------------------------------------------------------------------------------------ // +EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} + +#ifdef LINUX +static IBaseInterface *CreateInterfaceLocal( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : pModuleName - module name +// *pName - proc name +//----------------------------------------------------------------------------- +//static hlds_run wants to use this function +void *Sys_GetProcAddress( const char *pModuleName, const char *pName ) +{ + return GetProcAddress( GetModuleHandle(pModuleName), pName ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : pModuleName - module name +// *pName - proc name +//----------------------------------------------------------------------------- +// hlds_run wants to use this function +void *Sys_GetProcAddress( void *pModuleHandle, const char *pName ) +{ +#if defined ( _WIN32 ) + return GetProcAddress( (HINSTANCE)pModuleHandle, pName ); +#else + return GetProcAddress( pModuleHandle, pName ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Loads a DLL/component from disk and returns a handle to it +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +CSysModule *Sys_LoadModule( const char *pModuleName ) +{ +#if defined ( _WIN32 ) + HMODULE hDLL = LoadLibrary( pModuleName ); +#else + HMODULE hDLL = NULL; + char szAbsoluteModuleName[1024]; + szAbsoluteModuleName[0] = 0; + if ( pModuleName[0] != '/' ) + { + char szCwd[1024]; + char szAbsoluteModuleName[1024]; + + getcwd( szCwd, sizeof( szCwd ) ); + if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) + szCwd[ strlen( szCwd ) - 1 ] = 0; + + _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName ); + + hDLL = dlopen( szAbsoluteModuleName, RTLD_NOW ); + } + else + { + _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s", pModuleName ); + hDLL = dlopen( pModuleName, RTLD_NOW ); + } +#endif + + if( !hDLL ) + { + char str[512]; +#if defined ( _WIN32 ) + _snprintf( str, sizeof(str), "%s.dll", pModuleName ); + hDLL = LoadLibrary( str ); +#elif defined(OSX) + printf("Error:%s\n",dlerror()); + _snprintf( str, sizeof(str), "%s.dylib", szAbsoluteModuleName ); + hDLL = dlopen(str, RTLD_NOW); +#else + printf("Error:%s\n",dlerror()); + _snprintf( str, sizeof(str), "%s.so", szAbsoluteModuleName ); + hDLL = dlopen(str, RTLD_NOW); +#endif + } + + return reinterpret_cast(hDLL); +} + +//----------------------------------------------------------------------------- +// Purpose: Unloads a DLL/component from +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +void Sys_UnloadModule( CSysModule *pModule ) +{ + if ( !pModule ) + return; + + HMODULE hDLL = reinterpret_cast(pModule); +#if defined ( _WIN32 ) + FreeLibrary( hDLL ); +#else + dlclose((void *)hDLL); +#endif + +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : module - windows HMODULE from Sys_LoadModule() +// *pName - proc name +// Output : factory for this module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ) +{ + if ( !pModule ) + return NULL; + + HMODULE hDLL = reinterpret_cast(pModule); +#if defined ( _WIN32 ) + return reinterpret_cast(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); +#else +// Linux gives this error: +//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory +//(CSysModule *)) (const char *, int *)': +//../public/interface.cpp:154: ISO C++ forbids casting between +//pointer-to-function and pointer-to-object +// +// so lets get around it :) + return (CreateInterfaceFn)(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); +#endif +} + + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of this module +// Output : interface_instance_t +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactoryThis( void ) +{ +#ifdef LINUX + return CreateInterfaceLocal; +#else + return CreateInterface; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of the named module +// Input : *pModuleName - name of the module +// Output : interface_instance_t - instance of that module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( const char *pModuleName ) +{ +#if defined ( _WIN32 ) + return static_cast( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#else +// Linux gives this error: +//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory +//(const char *)) (const char *, int *)': +//../public/interface.cpp:186: invalid static_cast from type `void *' to +//type `IBaseInterface *(*) (const char *, int *)' +// +// so lets use the old style cast. + return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#endif +} diff --git a/sdk/common/interface.h b/metamod/include/public/interface.h similarity index 71% rename from sdk/common/interface.h rename to metamod/include/public/interface.h index b49d087..3349146 100644 --- a/sdk/common/interface.h +++ b/metamod/include/public/interface.h @@ -1,9 +1,3 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= // This header defines the interface convention used in the valve engine. // To make an interface and expose it: @@ -20,10 +14,27 @@ // for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and // expose it for the old interface. +//#if _MSC_VER >= 1300 // VC7 +//#include "tier1/interface.h" +//#else + #ifndef INTERFACE_H #define INTERFACE_H -#ifdef __cplusplus +#if !defined ( _WIN32 ) + +#include // dlopen,dlclose, et al +#include + +#define HMODULE void * +#define GetProcAddress dlsym + +#define _snprintf snprintf + +#endif + +void *Sys_GetProcAddress(const char *pModuleName, const char *pName); +void *Sys_GetProcAddress(void *pModuleHandle, const char *pName); // All interfaces derive from this. class IBaseInterface @@ -45,7 +56,7 @@ typedef IBaseInterface* (*InstantiateInterfaceFn)(); class InterfaceReg { public: - InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); public: @@ -68,6 +79,7 @@ public: // // A single class can support multiple interfaces through multiple inheritance // +// Use this if you want to write the factory function. #define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ static InterfaceReg __g_Create##className##_reg(functionName, versionName); @@ -77,7 +89,7 @@ public: // Use this to expose a singleton interface with a global variable you've created. #define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ - static IBaseInterface* __Create##className##interfaceName##_interface() {return (interfaceName *)&globalVarName;}\ + static IBaseInterface* __Create##className##interfaceName##_interface() {return (IBaseInterface *)&globalVarName;}\ static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); // Use this to expose a singleton interface. This creates the global variable for you automatically. @@ -86,10 +98,10 @@ public: EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) -#ifdef WIN32 +#ifdef _WIN32 #define EXPORT_FUNCTION __declspec(dllexport) #else - #define EXPORT_FUNCTION + #define EXPORT_FUNCTION __attribute__ ((visibility("default"))) #endif @@ -109,21 +121,30 @@ extern "C" }; -// Handle to an interface (HInterfaceModule_t* is just there for type safety). -typedef struct HInterfaceModule_t* HINTERFACEMODULE; - - -// Use these to load and unload a module. -extern HINTERFACEMODULE Sys_LoadModule(const char *pModuleName); -extern void Sys_FreeModule(HINTERFACEMODULE hModule); - -// Use these to get the factory function from either a loaded module or the current module. -extern CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ); extern CreateInterfaceFn Sys_GetFactoryThis( void ); -#endif // __cplusplus + +//----------------------------------------------------------------------------- +// UNDONE: This is obsolete, use the module load/unload/get instead!!! +//----------------------------------------------------------------------------- +extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); + + +// load/unload components +class CSysModule; + +//----------------------------------------------------------------------------- +// Load & Unload should be called in exactly one place for each module +// The factory for that module should be passed on to dependent components for +// proper versioning. +//----------------------------------------------------------------------------- +extern CSysModule *Sys_LoadModule( const char *pModuleName ); +extern void Sys_UnloadModule( CSysModule *pModule ); + +extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); + #endif - +//#endif // MSVC 6.0 diff --git a/metamod/include/public/protected_things.h b/metamod/include/public/protected_things.h new file mode 100644 index 0000000..201438e --- /dev/null +++ b/metamod/include/public/protected_things.h @@ -0,0 +1,187 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef PROTECTED_THINGS_H +#define PROTECTED_THINGS_H +#ifdef _WIN32 +#pragma once +#endif + + +// This header tries to prevent people from using potentially dangerous functions +// (like the notorious non-null-terminating strncpy) and functions that will break +// VCR mode (like time, input, registry, etc). +// +// This header should be included by ALL of our source code. + +// Eventually, ALL of these should be protected, but one man can only accomplish so much in +// one day AND work on features too! +#if defined( PROTECT_STRING_FUNCTIONS ) +#if defined( strncpy ) +#undef strncpy +#endif +#define strncpy strncpy__HEY_YOU__USE_VSTDLIB + + +#if defined( _snprintf ) +#undef _snprintf +#endif +#define _snprintf snprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( sprintf ) +#undef sprintf +#endif +#define sprintf sprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( _vsnprintf ) +#undef _vsnprintf +#endif +#define _vsnprintf vsnprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( strcat ) +#undef strcat +#endif +#define strcat strcat__HEY_YOU__USE_VSTDLIB +#endif + + +#if defined( PROTECT_FILEIO_FUNCTIONS ) +#if defined( fopen ) +#undef fopen +#endif +#define fopen fopen_USE_FILESYSTEM_INSTEAD +#endif + + +#if defined( PROTECTED_THINGS_ENABLE ) + +#if defined( GetTickCount ) +#undef GetTickCount +#endif +#define GetTickCount GetTickCount__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( timeGetTime ) +#undef timeGetTime +#endif +#define timeGetTime timeGetTime__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( clock ) +#undef clock +#endif +#define time time__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( recvfrom ) +#undef recvfrom +#endif +#define recvfrom recvfrom__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetCursorPos ) +#undef GetCursorPos +#endif +#define GetCursorPos GetCursorPos__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( ScreenToClient ) +#undef ScreenToClient +#endif +#define ScreenToClient ScreenToClient__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetCommandLine ) +#undef GetCommandLine +#endif +#define GetCommandLine GetCommandLine__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegOpenKeyEx ) +#undef RegOpenKeyEx +#endif +#define RegOpenKeyEx RegOpenKeyEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegOpenKey ) +#undef RegOpenKey +#endif +#define RegOpenKey RegOpenKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegSetValueEx ) +#undef RegSetValueEx +#endif +#define RegSetValueEx RegSetValueEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegSetValue ) +#undef RegSetValue +#endif +#define RegSetValue RegSetValue__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegQueryValueEx ) +#undef RegQueryValueEx +#endif +#define RegQueryValueEx RegQueryValueEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegQueryValue ) +#undef RegQueryValue +#endif +#define RegQueryValue RegQueryValue__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCreateKeyEx ) +#undef RegCreateKeyEx +#endif +#define RegCreateKeyEx RegCreateKeyEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCreateKey ) +#undef RegCreateKey +#endif +#define RegCreateKey RegCreateKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCloseKey ) +#undef RegCloseKey +#endif +#define RegCloseKey RegCloseKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetNumberOfConsoleInputEvents ) +#undef GetNumberOfConsoleInputEvents +#endif +#define GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( ReadConsoleInput ) +#undef ReadConsoleInput +#endif +#define ReadConsoleInput ReadConsoleInput__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetAsyncKeyState ) +#undef GetAsyncKeyState +#endif +#define GetAsyncKeyState GetAsyncKeyState__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetKeyState ) +#undef GetKeyState +#endif +#define GetKeyState GetKeyState__HEY_YOU__USE_PLATFORM_LIB + +#endif + + +#endif // PROTECTED_THINGS_H diff --git a/metamod/include/public/tier0/dbg.cpp b/metamod/include/public/tier0/dbg.cpp new file mode 100644 index 0000000..bca4c42 --- /dev/null +++ b/metamod/include/public/tier0/dbg.cpp @@ -0,0 +1,444 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library implementation +//============================================================================= + +#include "precompiled.h" +#include +#include +#include +#include +#include +#include +#include "tier0/dbg.h" +#include + + + +//----------------------------------------------------------------------------- +// internal structures +//----------------------------------------------------------------------------- + +#define MAX_GROUP_NAME_LENGTH 48 +//enum +//{ +// MAX_GROUP_NAME_LENGTH = 48 +//}; + +struct SpewGroup_t +{ + char m_GroupName[MAX_GROUP_NAME_LENGTH]; + int m_Level; +}; + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +void _AssertValidReadPtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadReadPtr(ptr, count)); +#else + Assert(ptr); +#endif + +} + +void _AssertValidWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadWritePtr(ptr, count)); +#else + Assert(ptr); +#endif +} + +void _AssertValidReadWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count))); +#else + Assert(ptr); +#endif +} + +void AssertValidStringPtr(const char* ptr, int maxchar/* = 0xFFFFFF */) +{ +#ifdef _WIN32 + Assert(!IsBadStringPtr(ptr, maxchar)); +#else + Assert(ptr); +#endif +} + + +//----------------------------------------------------------------------------- +// globals +//----------------------------------------------------------------------------- + +SpewRetval_t DefaultSpewFunc(SpewType_t type, char const *pMsg) +{ + printf("%s", pMsg); + if (type == SPEW_ASSERT) + return SPEW_DEBUGGER; + else if (type == SPEW_ERROR) + return SPEW_ABORT; + else + return SPEW_CONTINUE; +} + +static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc; + +static char const* s_pFileName; +static int s_Line; +static SpewType_t s_SpewType; + +static SpewGroup_t* s_pSpewGroups = 0; +static int s_GroupCount = 0; +static int s_DefaultLevel = 0; + + + +//----------------------------------------------------------------------------- +// Spew output management. +//----------------------------------------------------------------------------- + +void SpewOutputFunc(SpewOutputFunc_t func) +{ + s_SpewOutputFunc = func ? func : DefaultSpewFunc; +} + +SpewOutputFunc_t GetSpewOutputFunc(void) +{ + if (s_SpewOutputFunc) + { + return s_SpewOutputFunc; + } + else + { + return DefaultSpewFunc; + } +} + +//----------------------------------------------------------------------------- +// Spew functions +//----------------------------------------------------------------------------- + +void _SpewInfo(SpewType_t type, char const* pFile, int line) +{ + // Only grab the file name. Ignore the path. + char const* pSlash = strrchr(pFile, '\\'); + char const* pSlash2 = strrchr(pFile, '/'); + if (pSlash < pSlash2) pSlash = pSlash2; + + s_pFileName = pSlash ? pSlash + 1 : pFile; + s_Line = line; + s_SpewType = type; +} + +SpewRetval_t _SpewMessage(SpewType_t spewType, char const* pMsgFormat, va_list args) +{ + char pTempBuffer[1024]; + + /* Printf the file and line for warning + assert only... */ + int len = 0; + if ((spewType == SPEW_ASSERT)) + { + len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line); + } + + /* Create the message.... */ + len += vsprintf(&pTempBuffer[len], pMsgFormat, args); + + // Add \n for warning and assert + if ((spewType == SPEW_ASSERT)) + { + len += sprintf(&pTempBuffer[len], "\n"); + } + + assert(len < 1024); /* use normal assert here; to avoid recursion. */ + assert(s_SpewOutputFunc); + + /* direct it to the appropriate target(s) */ + SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer); + switch (ret) + { + // Put the break into the macro so it would occur in the right place + // case SPEW_DEBUGGER: + // DebuggerBreak(); + // break; + + case SPEW_ABORT: + // MessageBox(NULL,"Error in _SpewMessage","Error",MB_OK); + exit(0); + } + + return ret; +} + +SpewRetval_t _SpewMessage(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return SPEW_CONTINUE; + + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +void Msg(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DMsg(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void Warning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DWarning(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void Log(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DLog(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void Error(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_ERROR, pMsgFormat, args); + va_end(args); +} + + +//----------------------------------------------------------------------------- +// A couple of super-common dynamic spew messages, here for convenience +// These looked at the "developer" group, print if it's level 1 or higher +//----------------------------------------------------------------------------- + +void DevMsg(int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DevMsg(char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", 1)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// Find a group, return true if found, false if not. Return in ind the +// index of the found group, or the index of the group right before where the +// group should be inserted into the list to maintain sorted order. +//----------------------------------------------------------------------------- + +bool FindSpewGroup(char const* pGroupName, int* pInd) +{ + int s = 0; + if (s_GroupCount) + { + int e = (int)(s_GroupCount - 1); + while (s <= e) + { + int m = (s + e) >> 1; + int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName); + if (!cmp) + { + *pInd = m; + return true; + } + if (cmp < 0) + e = m - 1; + else + s = m + 1; + } + } + *pInd = s; + return false; +} + + +//----------------------------------------------------------------------------- +// Sets the priority level for a spew group +//----------------------------------------------------------------------------- + +void SpewActivate(char const* pGroupName, int level) +{ + Assert(pGroupName); + + // check for the default group first... + if ((pGroupName[0] == '*') && (pGroupName[1] == '\0')) + { + s_DefaultLevel = level; + return; + } + + // Normal case, search in group list using binary search. + // If not found, grow the list of groups and insert it into the + // right place to maintain sorted order. Then set the level. + int ind; + if (!FindSpewGroup(pGroupName, &ind)) + { + // not defined yet, insert an entry. + ++s_GroupCount; + if (s_pSpewGroups) + { + s_pSpewGroups = (SpewGroup_t*)realloc(s_pSpewGroups, + s_GroupCount * sizeof(SpewGroup_t)); + + // shift elements down to preserve order + int numToMove = s_GroupCount - ind - 1; + memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], + numToMove * sizeof(SpewGroup_t)); + } + else + s_pSpewGroups = (SpewGroup_t*)malloc(s_GroupCount * sizeof(SpewGroup_t)); + + Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH); + strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName); + } + s_pSpewGroups[ind].m_Level = level; +} + + +//----------------------------------------------------------------------------- +// Tests to see if a particular spew is active +//----------------------------------------------------------------------------- + +bool IsSpewActive(char const* pGroupName, int level) +{ + // If we don't find the spew group, use the default level. + int ind; + if (FindSpewGroup(pGroupName, &ind)) + return s_pSpewGroups[ind].m_Level >= level; + else + return s_DefaultLevel >= level; +} + + +// If we don't have a function from math.h, then it doesn't link certain floating-point +// functions in and printfs with %f cause runtime errors in the C libraries. +float CrackSmokingCompiler(float a) +{ + return fabs(a); +} + +void* Plat_SimpleLog(const char* file, int line) +{ + FILE* f = fopen("simple.log", "at+"); + fprintf(f, "%s:%i\n", file, line); + fclose(f); + + return NULL; +} \ No newline at end of file diff --git a/metamod/include/public/tier0/dbg.h b/metamod/include/public/tier0/dbg.h new file mode 100644 index 0000000..23b7b14 --- /dev/null +++ b/metamod/include/public/tier0/dbg.h @@ -0,0 +1,451 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library interfaces +//============================================================================= + + +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "basetypes.h" +#include "tier0/platform.h" +#include +#include +#include + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +#ifdef TIER0_DLL_EXPORT +#define DBG_INTERFACE DLL_EXPORT +#define DBG_OVERLOAD DLL_GLOBAL_EXPORT +#define DBG_CLASS DLL_CLASS_EXPORT +#else +#define DBG_INTERFACE DLL_IMPORT +#define DBG_OVERLOAD DLL_GLOBAL_IMPORT +#define DBG_CLASS DLL_CLASS_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Spew. +// +// Spew can be used in a static and a dynamic mode. The static +// mode allows us to display assertions and other messages either only +// in debug builds, or in non-release builds. The dynamic mode allows us to +// turn on and off certain spew messages while the application is running. +// +// Static Spew messages: +// +// Assertions are used to detect and warn about invalid states +// Spews are used to display a particular status/warning message. +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// To use a warning, use +// +// Warning("Oh I feel so %s all over\n", "yummy"); +// +// Warning will do its magic in only Debug builds. To perform spew in *all* +// builds, use RelWarning. +// +// Three other spew types, Msg, Log, and Error, are compiled into all builds. +// These error types do *not* need two sets of parenthesis. +// +// Msg( "Isn't this exciting %d?", 5 ); +// Error( "I'm just thrilled" ); +// +// Dynamic Spew messages +// +// It is possible to dynamically turn spew on and off. Dynamic spew is +// identified by a spew group and priority level. To turn spew on for a +// particular spew group, use SpewActivate( "group", level ). This will +// cause all spew in that particular group with priority levels <= the +// level specified in the SpewActivate function to be printed. Use DSpew +// to perform the spew: +// +// DWarning( "group", level, "Oh I feel even yummier!\n" ); +// +// Priority level 0 means that the spew will *always* be printed, and group +// '*' is the default spew group. If a DWarning is encountered using a group +// whose priority has not been set, it will use the priority of the default +// group. The priority of the default group is initially set to 0. +// +// Spew output +// +// The output of the spew system can be redirected to an externally-supplied +// function which is responsible for outputting the spew. By default, the +// spew is simply printed using printf. +// +// To redirect spew output, call SpewOutput. +// +// SpewOutputFunc( OutputFunc ); +// +// This will cause OutputFunc to be called every time a spew message is +// generated. OutputFunc will be passed a spew type and a message to print. +// It must return a value indicating whether the debugger should be invoked, +// whether the program should continue running, or whether the program +// should abort. +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +/* Various types of spew messages */ +// I'm sure you're asking yourself why SPEW_ instead of DBG_ ? +// It's because DBG_ is used all over the place in windows.h +// For example, DBG_CONTINUE is defined. Feh. +enum SpewType_t +{ + SPEW_MESSAGE = 0, + SPEW_WARNING, + SPEW_ASSERT, + SPEW_ERROR, + SPEW_LOG, + + SPEW_TYPE_COUNT +}; + +enum SpewRetval_t +{ + SPEW_DEBUGGER = 0, + SPEW_CONTINUE, + SPEW_ABORT +}; + +/* type of externally defined function used to display debug spew */ +typedef SpewRetval_t(*SpewOutputFunc_t)(SpewType_t spewType, char const *pMsg); + +/* Used to redirect spew output */ +void SpewOutputFunc(SpewOutputFunc_t func); + +/* Used ot get the current spew output function */ +SpewOutputFunc_t GetSpewOutputFunc(void); + +/* Used to manage spew groups and subgroups */ +void SpewActivate(char const* pGroupName, int level); +bool IsSpewActive(char const* pGroupName, int level); + +/* Used to display messages, should never be called directly. */ +void _SpewInfo(SpewType_t type, char const* pFile, int line); +SpewRetval_t _SpewMessage(char const* pMsg, ...); +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsg, ...); + +/* Used to define macros, never use these directly. */ +#define _Assert( _exp ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertMsg( _exp, _msg ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFunc( _exp, _f ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ + _f; \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertEquals( _exp, _expectedValue ) \ + do { \ + if ((_exp) != (_expectedValue)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFloatEquals( _exp, _expectedValue, _tol ) \ + do { \ + if (fabs((_exp) - (_expectedValue)) > (_tol)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +/* Spew macros... */ + +#ifdef _DEBUG + +#define Assert( _exp ) _Assert( _exp ) +#define AssertMsg( _exp, _msg ) _AssertMsg( _exp, _msg ) +#define AssertFunc( _exp, _f ) _AssertFunc( _exp, _f ) +#define AssertEquals( _exp, _expectedValue ) _AssertEquals( _exp, _expectedValue ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) _AssertFloatEquals( _exp, _expectedValue, _tol ) +#define Verify( _exp ) _Assert( _exp ) + +#define AssertMsg1( _exp, _msg, a1 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1 ) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2 ) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3 ) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4 ) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ) + + +#else /* Not _DEBUG */ + +#define Assert( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif /* _DEBUG */ + + + +/* These are always compiled in */ +void Msg(char const* pMsg, ...); +void DMsg(char const *pGroupName, int level, char const *pMsg, ...); + +void Warning(char const *pMsg, ...); +void DWarning(char const *pGroupName, int level, char const *pMsg, ...); + +void Log(char const *pMsg, ...); +void DLog(char const *pGroupName, int level, char const *pMsg, ...); + +void Error(char const *pMsg, ...); + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +/* A couple of super-common dynamic spew messages, here for convenience */ +/* These looked at the "developer" group */ +void DevMsg(int level, char const* pMsg, ...); +void DevWarning(int level, char const *pMsg, ...); +void DevLog(int level, char const *pMsg, ...); + +/* default level versions (level 1) */ +void DevMsg(char const* pMsg, ...); +void DevWarning(char const *pMsg, ...); +void DevLog(char const *pMsg, ...); + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) + + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +void _AssertValidReadPtr(void* ptr, int count = 1); +void _AssertValidWritePtr(void* ptr, int count = 1); +void _AssertValidReadWritePtr(void* ptr, int count = 1); + + void AssertValidStringPtr(const char* ptr, int maxchar = 0xFFFFFF); +template inline void AssertValidReadPtr(T* ptr, int count = 1) { _AssertValidReadPtr((void*)ptr, count); } +template inline void AssertValidWritePtr(T* ptr, int count = 1) { _AssertValidWritePtr((void*)ptr, count); } +template inline void AssertValidReadWritePtr(T* ptr, int count = 1) { _AssertValidReadWritePtr((void*)ptr, count); } + +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const char *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf) - 1] = 0; + } + + operator const char *() const + { + return m_szBuf; + } + +private: + char m_szBuf[256]; +}; + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// +//#ifdef _WIN32 +//#ifdef _DEBUG +//#pragma comment(compiler) +//#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") +//#endif +//#endif + +#endif /* DBG_H */ \ No newline at end of file diff --git a/metamod/include/public/tier0/platform.h b/metamod/include/public/tier0/platform.h new file mode 100644 index 0000000..f9e4e6c --- /dev/null +++ b/metamod/include/public/tier0/platform.h @@ -0,0 +1,630 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Extremely low-level platform-specific stuff +//============================================================================= + + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" + +// need this for _alloca +#include + +// need this for memset +#include + +#include "archtypes.h" + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +// This can be used to ensure the size of pointers to members when declaring +// a pointer type for a class that has only been forward declared +#ifdef _MSC_VER +#define SINGLE_INHERITANCE __single_inheritance +#define MULTIPLE_INHERITANCE __multiple_inheritance +#else +#define SINGLE_INHERITANCE +#define MULTIPLE_INHERITANCE +#endif + +/* +FIXME: Enable this when we no longer fear change =) + +// need these for the limits +#include +#include + +// Maximum and minimum representable values +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN +*/ + +// portability / compiler settings +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#elif __linux__ +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#endif // defined(_WIN32) && !defined(WINDED) + + +// Defines MAX_PATH +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// Used to step into the debugger +#define DebuggerBreak() __asm { int 3 } + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#else +#define EXPORT /* */ +#endif +#endif + +#if defined __i386__ && !defined __linux__ +#define id386 1 +#else +#define id386 0 +#endif // __i386__ + +#ifdef _WIN32 +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" __declspec( dllexport ) +#define DLL_IMPORT extern "C" __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT __declspec( dllexport ) +#define DLL_CLASS_IMPORT __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) +#define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) +#elif defined __linux__ + +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" +#define DLL_IMPORT extern "C" + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT +#define DLL_CLASS_IMPORT + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern +#define DLL_GLOBAL_IMPORT extern + +#else +#error "Unsupported Platform." +#endif + +// Used for standard calling conventions +#ifdef _WIN32 +#define FASTCALL __fastcall +#define FORCEINLINE __forceinline +#else +#define FASTCALL +#define FORCEINLINE inline +#endif + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Pass hints to the compiler to prevent it from generating unnessecary / stupid code +// in certain situations. Several compilers other than MSVC also have an equivilent +// construct. +// +// Essentially the 'Hint' is that the condition specified is assumed to be true at +// that point in the compilation. If '0' is passed, then the compiler assumes that +// any subsequent code in the same 'basic block' is unreachable, and thus usually +// removed. +#ifdef _MSC_VER +#define HINT(THE_HINT) __assume((THE_HINT)) +#else +#define HINT(THE_HINT) 0 +#endif + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + +#ifdef _WIN32 +// Alloca defined for this platform +#define stackalloc( _size ) _alloca( _size ) +#define stackfree( _p ) 0 +#elif __linux__ +// Alloca defined for this platform +#define stackalloc( _size ) alloca( _size ) +#define stackfree( _p ) 0 +#endif + +#ifdef _WIN32 +// Remove warnings from warning level 4. +#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed +#pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter +#pragma warning(disable : 4127) // warning C4127: conditional expression is constant +#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable : 4706) // warning C4706: assignment within conditional expression +#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined +#pragma warning(disable : 4702) // warning C4702: unreachable code +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4239) // nonstandard extension used : 'argument' ( conversion from class Vector to class Vector& ) +#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for class-name 'CFlexCycler::CBaseFlex' +#pragma warning(disable : 4324) // Padding was added at the end of a structure +#pragma warning(disable : 4244) // type conversion warning. +#pragma warning(disable : 4305) // truncation from 'const double ' to 'float ' +#pragma warning(disable : 4786) // Disable warnings about long symbol names + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) // Disable warnings about private copy constructors +#endif +#endif +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template +inline T WordSwapC(T w) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC(T dw) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#ifdef _MSC_VER + +#define WordSwap WordSwapAsm +#define DWordSwap DWordSwapAsm + +#pragma warning(push) +#pragma warning (disable:4035) // no return value + +template +inline T WordSwapAsm(T w) +{ + __asm + { + mov ax, w + xchg al, ah + } +} + +template +inline T DWordSwapAsm(T dw) +{ + __asm + { + mov eax, dw + bswap eax + } +} + +#pragma warning(pop) + +// The assembly implementation is not compatible with floats +template <> +inline float DWordSwapAsm(float f) +{ + return DWordSwapC(f); +} + +#else + +#define WordSwap WordSwapC +#define DWordSwap DWordSwapC + +#endif + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined(__i386__) +#define VALVE_LITTLE_ENDIAN 1 +#endif + +#ifdef _SGI_SOURCE +#define VALVE_BIG_ENDIAN 1 +#endif + +#if defined(VALVE_LITTLE_ENDIAN) + +#define Valve_BigShort( val ) WordSwap( val ) +#define Valve_BigWord( val ) WordSwap( val ) +#define Valve_BigLong( val ) DWordSwap( val ) +#define Valve_BigDWord( val ) DWordSwap( val ) +#define Valve_BigFloat( val ) DWordSwap( val ) +#define Valve_LittleShort( val ) ( val ) +#define Valve_LittleWord( val ) ( val ) +#define Valve_LittleLong( val ) ( val ) +#define Valve_LittleDWord( val ) ( val ) +#define Valve_LittleFloat( val ) ( val ) + +#elif defined(BIG_ENDIAN) + +#define Valve_BigShort( val ) ( val ) +#define Valve_BigWord( val ) ( val ) +#define Valve_BigLong( val ) ( val ) +#define Valve_BigDWord( val ) ( val ) +#define Valve_BigFloat( val ) ( val ) +#define Valve_LittleShort( val ) WordSwap( val ) +#define Valve_LittleWord( val ) WordSwap( val ) +#define Valve_LittleLong( val ) DWordSwap( val ) +#define Valve_LittleDWord( val ) DWordSwap( val ) +#define Valve_LittleFloat( val ) DWordSwap( val ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort(short val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline uint16 BigWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline long BigLong(long val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline uint32 BigDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline float BigFloat(float val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline short LittleShort(short val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline uint16 LittleWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline long LittleLong(long val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline uint32 LittleDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline float LittleFloat(float val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } + +#endif + + + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#endif + +/* +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE unsigned long Plat_MSTime(); // Time in milliseconds. + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime +*/ + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + unsigned char m_nLogicalProcessors, // Number op logical processors. + m_nPhysicalProcessors; // Number of physical processors + + int64 m_Speed; // In cycles per second. + + char* m_szProcessorID; // Processor vendor Identification. +}; + +PLATFORM_INTERFACE const CPUInformation& GetCPUInformation(); + + +//----------------------------------------------------------------------------- +// Thread related functions +//----------------------------------------------------------------------------- +// Registers the current thread with Tier0's thread management system. +// This should be called on every thread created in the game. +PLATFORM_INTERFACE unsigned long Plat_RegisterThread(const char *pName = "Source Thread"); + +// Registers the current thread as the primary thread. +PLATFORM_INTERFACE unsigned long Plat_RegisterPrimaryThread(); + +// VC-specific. Sets the thread's name so it has a friendly name in the debugger. +// This should generally only be handled by Plat_RegisterThread and Plat_RegisterPrimaryThread +PLATFORM_INTERFACE void Plat_SetThreadName(unsigned long dwThreadID, const char *pName); + +// These would be private if it were possible to export private variables from a .DLL. +// They need to be variables because they are checked by inline functions at performance +// critical places. +PLATFORM_INTERFACE unsigned long Plat_PrimaryThreadID; + +// Returns the ID of the currently executing thread. +PLATFORM_INTERFACE unsigned long Plat_GetCurrentThreadID(); + +// Returns the ID of the primary thread. +inline unsigned long Plat_GetPrimaryThreadID() +{ + return Plat_PrimaryThreadID; +} + +// Returns true if the current thread is the primary thread. +inline bool Plat_IsPrimaryThread() +{ + //return true; + return (Plat_GetPrimaryThreadID() == Plat_GetCurrentThreadID()); +} + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + + + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +//#include "tier0/fasttimer.h" + + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +void* Plat_SimpleLog(const char* file, int line); + +//#define Plat_dynamic_cast Plat_SimpleLog(__FILE__,__LINE__),dynamic_cast + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template +inline void Construct(T* pMemory) +{ + new(pMemory)T; +} + +template +inline void CopyConstruct(T* pMemory, T const& src) +{ + new(pMemory)T(src); +} + +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset(pMemory, 0xDD, sizeof(T)); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (char *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + +(Note added to platform.h so platforms that correctly support templated +functions can handle portions as templated functions rather than wrapped +functions) + +Helps automate the process of creating an array of function +templates that are all specialized by a single integer. +This sort of thing is often useful in optimization work. + +For example, using TEMPLATE_FUNCTION_TABLE, this: + +TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) +{ +return argument * argument; +} + +is equivilent to the following: + +(NOTE: the function has to be wrapped in a class due to code +generation bugs involved with directly specializing a function +based on a constant.) + +template +class FunctionWrapper +{ +public: +int Function( int blah, int blah ) +{ +return argument*argument; +} +} + +typedef int (*FunctionType)( int blah, int blah ); + +class FunctionName +{ +public: +enum { count = 10 }; +FunctionType functions[10]; +}; + +FunctionType FunctionName::functions[] = +{ +FunctionWrapper<0>::Function, +FunctionWrapper<1>::Function, +FunctionWrapper<2>::Function, +FunctionWrapper<3>::Function, +FunctionWrapper<4>::Function, +FunctionWrapper<5>::Function, +FunctionWrapper<6>::Function, +FunctionWrapper<7>::Function, +FunctionWrapper<8>::Function, +FunctionWrapper<9>::Function +}; +*/ + +bool vtune(bool resume); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template \ +RETURN_TYPE FASTCALL __Function_##NAME::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + + +#endif /* PLATFORM_H */ \ No newline at end of file diff --git a/metamod/include/public/utlmemory.h b/metamod/include/public/utlmemory.h new file mode 100644 index 0000000..4f75f81 --- /dev/null +++ b/metamod/include/public/utlmemory.h @@ -0,0 +1,357 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef UTLMEMORY_H +#define UTLMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "tier0/dbg.h" +#include + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +/*template +inline void Construct(T *pMemory) +{ + ::new(pMemory) T; +} + +template +inline void CopyConstruct(T *pMemory,T const& src) +{ + ::new(pMemory) T(src); +} + +template +inline void Destruct(T *pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset(pMemory,0xDD,sizeof(T)); +#endif +}*/ +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T > +class CUtlMemory +{ +public: + // constructor, destructor + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + ~CUtlMemory(); + + // element access + T& operator[](int i); + T const& operator[](int i) const; + T& Element(int i); + T const& Element(int i) const; + + // Can we use this index? + bool IsIdxValid(int i) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Attaches the buffer to external memory.... + void SetExternalBuffer(T* pMemory, int numElements); + + // Size + int NumAllocated() const; + int Count() const; + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow(int num = 1); + + // Makes sure we've got at least this much memory + void EnsureCapacity(int num); + + // Memory deallocation + void Purge(); + + // is the memory externally allocated? + bool IsExternallyAllocated() const; + + // Set the size by which the memory grows + void SetGrowSize(int size); + +private: + enum + { + EXTERNAL_BUFFER_MARKER = -1, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T > +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) : m_pMemory(0), +m_nAllocationCount(nInitAllocationCount), m_nGrowSize(nGrowSize) +{ + Assert((nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER)); + if (m_nAllocationCount) + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T > +CUtlMemory::CUtlMemory(T* pMemory, int numElements) : m_pMemory(pMemory), +m_nAllocationCount(numElements) +{ + // Special marker indicating externally supplied memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T > +CUtlMemory::~CUtlMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::SetExternalBuffer(T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlMemory::operator[](int i) +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::operator[](int i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T& CUtlMemory::Element(int i) +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::Element(int i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlMemory::IsExternallyAllocated() const +{ + return m_nGrowSize == EXTERNAL_BUFFER_MARKER; +} + + +template< class T > +void CUtlMemory::SetGrowSize(int nSize) +{ + Assert((nSize >= 0) && (nSize != EXTERNAL_BUFFER_MARKER)); + m_nGrowSize = nSize; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T > +inline T* CUtlMemory::Base() +{ + return m_pMemory; +} + +template< class T > +inline T const* CUtlMemory::Base() const +{ + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T > +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlMemory::IsIdxValid(int i) const +{ + return (i >= 0) && (i < m_nAllocationCount); +} + + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::Grow(int num) +{ + Assert(num > 0); + + if (IsExternallyAllocated()) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = m_nAllocationCount + num; + while (m_nAllocationCount < nAllocationRequested) + { + if (m_nAllocationCount != 0) + { + if (m_nGrowSize) + { + m_nAllocationCount += m_nGrowSize; + } + else + { + m_nAllocationCount += m_nAllocationCount; + } + } + else + { + // Compute an allocation which is at least as big as a cache line... + m_nAllocationCount = (31 + sizeof(T)) / sizeof(T); + Assert(m_nAllocationCount != 0); + } + } + + if (m_pMemory) + { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T > +inline void CUtlMemory::EnsureCapacity(int num) +{ + if (m_nAllocationCount >= num) + return; + + if (IsExternallyAllocated()) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + m_nAllocationCount = num; + if (m_pMemory) + { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::Purge() +{ + if (!IsExternallyAllocated()) + { + if (m_pMemory) + { + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + +#endif // UTLMEMORY_H diff --git a/metamod/include/public/utlvector.h b/metamod/include/public/utlvector.h new file mode 100644 index 0000000..263e72f --- /dev/null +++ b/metamod/include/public/utlvector.h @@ -0,0 +1,565 @@ +#ifndef UTLVECTOR_H +#define UTLVECTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmemory.h" + +template +class CUtlVector +{ +public: + typedef T ElemType_t; + + // constructor, destructor + CUtlVector(int growSize = 0, int initSize = 0); + CUtlVector(T* pMemory, int numElements); + ~CUtlVector(); + + // Copy the array. + CUtlVector& operator=(const CUtlVector &other); + + // element access + T& operator[](int i); + T const& operator[](int i) const; + T& Element(int i); + T const& Element(int i) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Returns the number of elements in the vector + // SIZE IS DEPRECATED! + int Count() const; + int Size() const; // don't use me! + + // Is element index valid? + bool IsValidIndex(int i) const; + static int InvalidIndex(void); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore(int elem); + int InsertAfter(int elem); + + // Adds an element, uses copy constructor + int AddToHead(T const& src); + int AddToTail(T const& src); + int InsertBefore(int elem, T const& src); + int InsertAfter(int elem, T const& src); + + // Adds multiple elements, uses default constructor + int AddMultipleToHead(int num); + int AddMultipleToTail(int num, const T *pToCopy=NULL); + int InsertMultipleBefore(int elem, int num, const T *pToCopy=NULL); // If pToCopy is set, then it's an array of length 'num' and + int InsertMultipleAfter(int elem, int num); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize(int size); + void SetCount(int count); + + // Calls SetSize and copies each element. + void CopyArray(T const *pArray, int size); + + // Add the specified array to the tail. + int AddVectorToTail(CUtlVector const &src); + + // Finds an element (element needs operator== defined) + int Find(T const& src) const; + + bool HasElement(T const& src); + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity(int num); + + // Makes sure we have at least this many elements + void EnsureCount(int num); + + // Element removal + void FastRemove(int elem); // doesn't preserve order + void Remove(int elem); // preserves order, shifts elements + void FindAndRemove(T const& src); // removes first occurrence of src, preserves order, shifts elements + void RemoveMultiple(int elem, int num); // preserves order, shifts elements + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize(int size); + +protected: + // Can't copy this unless we explicitly do it! + CUtlVector(CUtlVector const& vec) { assert(0); } + + // Grows the vector + void GrowVector(int num = 1); + + // Shifts elements.... + void ShiftElementsRight(int elem, int num = 1); + void ShiftElementsLeft(int elem, int num = 1); + + // For easier access to the elements through the debugger + void ResetDbgInfo(); + + CUtlMemory m_Memory; + int m_Size; + + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; +}; + +//----------------------------------------------------------------------------- +// For easier access to the elements through the debugger +//----------------------------------------------------------------------------- + +template< class T > +inline void CUtlVector::ResetDbgInfo() +{ + m_pElements = m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +inline CUtlVector::CUtlVector(int growSize, int initSize) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::CUtlVector(T* pMemory, int numElements) : + m_Memory(pMemory, numElements), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::~CUtlVector() +{ + Purge(); +} + +template +inline CUtlVector& CUtlVector::operator=(const CUtlVector &other) +{ + CopyArray(other.Base(), other.Count()); + return *this; +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T > +inline T& CUtlVector::operator[](int i) +{ + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::operator[](int i) const +{ + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T& CUtlVector::Element(int i) +{ + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::Element(int i) const +{ + assert(IsValidIndex(i)); + return m_Memory[i]; +} + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- + +template< class T > +inline T* CUtlVector::Base() +{ + return m_Memory.Base(); +} + +template< class T > +inline T const* CUtlVector::Base() const +{ + return m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::Size() const +{ + return m_Size; +} + +template< class T > +inline int CUtlVector::Count() const +{ + return m_Size; +} + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T > +inline bool CUtlVector::IsValidIndex(int i) const +{ + return (i >= 0) && (i < m_Size); +} + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlVector::InvalidIndex(void) +{ + return -1; +} + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::GrowVector(int num) +{ + if (m_Size + num - 1 >= m_Memory.NumAllocated()) + { + m_Memory.Grow(m_Size + num - m_Memory.NumAllocated()); + } + + m_Size += num; + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::EnsureCapacity(int num) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::EnsureCount(int num) +{ + if (Count() < num) + AddMultipleToTail(num - Count()); +} + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::ShiftElementsRight(int elem, int num) +{ + assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + memmove(&Element(elem+num), &Element(elem), numToMove * sizeof(T)); +} + +template< class T > +void CUtlVector::ShiftElementsLeft(int elem, int num) +{ + assert(IsValidIndex(elem) || (m_Size == 0) || (num == 0)); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + memmove(&Element(elem), &Element(elem+num), numToMove * sizeof(T)); + +#ifdef _DEBUG + memset(&Element(m_Size-num), 0xDD, num * sizeof(T)); +#endif + } +} + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} + +template< class T > +inline int CUtlVector::AddToTail() +{ + return InsertBefore(m_Size); +} + +template< class T > +inline int CUtlVector::InsertAfter(int elem) +{ + return InsertBefore(elem + 1); +} + +template< class T > +int CUtlVector::InsertBefore(int elem) +{ + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + Construct(&Element(elem)); + return elem; +} + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddToHead(T const& src) +{ + return InsertBefore(0, src); +} + +template< class T > +inline int CUtlVector::AddToTail(T const& src) +{ + return InsertBefore(m_Size, src); +} + +template< class T > +inline int CUtlVector::InsertAfter(int elem, T const& src) +{ + return InsertBefore(elem + 1, src); +} + +template< class T > +int CUtlVector::InsertBefore(int elem, T const& src) +{ + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct(&Element(elem), src); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddMultipleToHead(int num) +{ + return InsertMultipleBefore(0, num); +} + +template< class T > +inline int CUtlVector::AddMultipleToTail(int num, const T *pToCopy) +{ + return InsertMultipleBefore(m_Size, num, pToCopy); +} + +template< class T > +int CUtlVector::InsertMultipleAfter(int elem, int num) +{ + return InsertMultipleBefore(elem + 1, num); +} + + +template< class T > +void CUtlVector::SetCount(int count) +{ + RemoveAll(); + AddMultipleToTail(count); +} + +template< class T > +inline void CUtlVector::SetSize(int size) +{ + SetCount(size); +} + +template< class T > +void CUtlVector::CopyArray(T const *pArray, int size) +{ + SetSize(size); + for(int i=0; i < size; i++) + (*this)[i] = pArray[i]; +} + +template< class T > +int CUtlVector::AddVectorToTail(CUtlVector const &src) +{ + int base = Count(); + + // Make space. + AddMultipleToTail(src.Count()); + + // Copy the elements. + for (int i=0; i < src.Count(); i++) + (*this)[base + i] = src[i]; + + return base; +} + +template< class T > +inline int CUtlVector::InsertMultipleBefore(int elem, int num, const T *pToInsert) +{ + if(num == 0) + return elem; + + // Can insert at the end + assert((elem == Count()) || IsValidIndex(elem)); + + GrowVector(num); + ShiftElementsRight(elem, num); + + // Invoke default constructors + for (int i = 0; i < num; ++i) + Construct(&Element(elem+i)); + + // Copy stuff in? + if (pToInsert) + { + for (int i=0; i < num; i++) + { + Element(elem+i) = pToInsert[i]; + } + } + + return elem; +} + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< class T > +int CUtlVector::Find(T const& src) const +{ + for (int i = 0; i < Count(); ++i) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< class T > +bool CUtlVector::HasElement(T const& src) +{ + return (Find(src) >= 0); +} + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::FastRemove(int elem) +{ + assert(IsValidIndex(elem)); + + Destruct(&Element(elem)); + if (m_Size > 0) + { + Q_memcpy(&Element(elem), &Element(m_Size-1), sizeof(T)); + --m_Size; + } +} + +template< class T > +void CUtlVector::Remove(int elem) +{ + Destruct(&Element(elem)); + ShiftElementsLeft(elem); + --m_Size; +} + +template< class T > +void CUtlVector::FindAndRemove(T const& src) +{ + int elem = Find(src); + if (elem != -1) + { + Remove(elem); + } +} + +template< class T > +void CUtlVector::RemoveMultiple(int elem, int num) +{ + assert(IsValidIndex(elem)); + assert(elem + num <= Count()); + + for (int i = elem + num; --i >= elem;) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< class T > +void CUtlVector::RemoveAll() +{ + for (int i = m_Size; --i >= 0;) + Destruct(&Element(i)); + + m_Size = 0; +} + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + ResetDbgInfo(); +} + +template +inline void CUtlVector::PurgeAndDeleteElements() +{ + for (int i = 0; i < m_Size; i++) + delete Element(i); + + Purge(); +} + +template< class T > +void CUtlVector::SetGrowSize(int size) +{ + m_Memory.SetGrowSize(size); +} + +#endif // CCVECTOR_H diff --git a/metamod/msvc/PostBuild.bat b/metamod/msvc/PostBuild.bat new file mode 100644 index 0000000..8583878 --- /dev/null +++ b/metamod/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/metamod/msvc/PreBuild.bat b/metamod/msvc/PreBuild.bat new file mode 100644 index 0000000..d456330 --- /dev/null +++ b/metamod/msvc/PreBuild.bat @@ -0,0 +1,241 @@ +@setlocal enableextensions enabledelayedexpansion +@echo off +:: +:: Pre-build auto-versioning script +:: + +set srcdir=%~1 +set repodir=%~2 + +set old_version= +set old_specialbuild="" +set version_revision=0 +set version_specialbuild= +set version_id_commit= +set version_author_commit= +set version_pdate_1=%date:~-4%-%date:~3,2%-%date:~0,2% +set version_pdate=%version_pdate_1%%time:~0,2%:%time:~3,2%:%time:~6,2% +set version_pdate_2=%time:~0,2%-%time:~3,2%-%time:~6,2% +set version_pdate_2=%version_pdate_2: =% +set version_date=%version_pdate_1%__%version_pdate_2% +set version_major=0 +set version_minor=0 +set version_specialversion= +set url_commit= + +:: +:: Check for git.exe presence +:: +CALL git.exe describe >NUL 2>&1 +set errlvl="%ERRORLEVEL%" + +:: +:: Read old appversion.h, if present +:: +IF EXIST "%srcdir%\appversion.h" ( + FOR /F "usebackq tokens=1,2,3" %%i in ("%srcdir%\appversion.h") do ( + IF %%i==#define ( + IF %%j==APP_VERSION_C set old_version=%%k + IF %%j==APP_VERSION_SPECIALBUILD set old_specialbuild=%%k + ) + ) +) + +IF %errlvl% == "1" ( + echo can't locate git.exe - auto-versioning step won't be performed + + :: if we haven't appversion.h, we need to create it + IF NOT "%old_version%" == "" ( + set version_revision=0 + ) +) + +:: +:: Read major, minor and maintenance version components from Version.h +:: +IF EXIST "%srcdir%\version.h" ( + FOR /F "usebackq tokens=1,2,3" %%i in ("%srcdir%\version.h") do ( + IF %%i==#define ( + IF %%j==VERSION_MAJOR set version_major=%%k + IF %%j==VERSION_MINOR set version_minor=%%k + IF %%j==VERSION_SPECIALVERSION set version_specialversion=%%k + ) + ) +) ELSE ( + FOR /F "usebackq tokens=1,2,3,* delims==" %%i in ("%repodir%..\gradle.properties") do ( + IF NOT [%%j] == [] ( + IF %%i==majorVersion set version_major=%%j + IF %%i==minorVersion set version_minor=%%j + IF %%i==specialVersion set version_specialversion=%%j + ) + ) +) + +:: +:: Read revision and release date from it +:: +IF NOT %errlvl% == "1" ( + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." rev-list --all | wc -l"') DO ( + IF NOT [%%i] == [] ( + set version_revision=%%i + ) + ) +) + +:: +:: Now form full version string like 1.0.0.1 +:: + +set new_version=%version_major%,%version_minor%,0,%version_revision% + +:: +:: Get remote url repository +:: +IF NOT %errlvl% == "1" ( + + set branch_name=master + set branch_remote=origin + :: Get current branch + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." rev-parse --abbrev-ref HEAD"') DO ( + set branch_name=%%i + ) + :: Get remote name by current branch + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." config branch.!branch_name!.remote"') DO ( + set branch_remote=%%i + ) + :: Get remote url + FOR /F "tokens=2 delims=@" %%i IN ('"git -C "%repodir%\." config remote.!branch_remote!.url"') DO ( + set url_commit=%%i + ) + :: Get author last no-merge commit + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." log -1 --no-merges --pretty=format:%%an"') DO ( + set version_author_commit=%%i + ) + :: Get commit id + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." rev-parse --verify HEAD"') DO ( + set var=%%i + set version_id_commit=!var:~0,+7! + ) + + IF [!url_commit!] == [] ( + + FOR /F "tokens=1" %%i IN ('"git -C "%repodir%\." config remote.!branch_remote!.url"') DO ( + set url_commit=%%i + ) + + :: strip .git + if "x!url_commit:~-4!"=="x.git" ( + set url_commit=!url_commit:~0,-4! + ) + + :: append extra string + If NOT "%url_commit%"=="%url_commit:bitbucket.org=%" ( + set url_commit=!url_commit!/commits/ + ) ELSE ( + set url_commit=!url_commit!/commit/ + ) + + ) ELSE ( + :: strip .git + if "x!url_commit:~-4!"=="x.git" ( + set url_commit=!url_commit:~0,-4! + ) + :: replace : to / + set url_commit=!url_commit::=/! + + :: append extra string + If NOT "%url_commit%"=="%url_commit:bitbucket.org=%" ( + set url_commit=https://!url_commit!/commits/ + ) ELSE ( + set url_commit=https://!url_commit!/commit/ + ) + ) +) + +:: +:: Detect local modifications +:: +set localChanged=0 +IF NOT %errlvl% == "1" ( + FOR /F "tokens=*" %%i IN ('"git -C "%repodir%\." ls-files -m"') DO ( + set localChanged=1 + ) +) + +IF [%localChanged%]==[1] ( + IF NOT [%version_specialversion%] == [] ( + set version_specialbuild=%version_specialversion% + ) ELSE ( + set version_specialbuild=m + ) +) ELSE ( + set version_specialbuild= +) + +:: +:: Update appversion.h if version has changed or modifications/mixed revisions detected +:: +IF NOT "%new_version%"=="%old_version%" goto _update +IF NOT "%version_specialbuild%"==%old_specialbuild% goto _update +goto _exit + +:_update +echo Updating appversion.h, new version is "%new_version%", the old one was "%old_version%" +echo new special build is "%version_specialbuild%", the old one was %old_specialbuild% + +echo #ifndef __APPVERSION_H__>"%srcdir%\appversion.h" +echo #define __APPVERSION_H__>>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo // >>"%srcdir%\appversion.h" +echo // This file is generated automatically.>>"%srcdir%\appversion.h" +echo // Don't edit it.>>"%srcdir%\appversion.h" +echo // >>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo // Version defines>>"%srcdir%\appversion.h" + +IF "%version_specialversion%" == "" ( + echo #define APP_VERSION_D %version_major%.%version_minor%.%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD_RC "%version_major%.%version_minor%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_C %version_major%,%version_minor%,0,%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRCS "%version_major%,%version_minor%,0,%version_revision%">>"%srcdir%\appversion.h" +) ELSE ( + echo #define APP_VERSION_D %version_major%.%version_minor%.%version_maintenance%.%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%version_maintenance%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD_RC "%version_major%.%version_minor%.%version_maintenance%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_C %version_major%,%version_minor%,%version_maintenance%,%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRCS "%version_major%,%version_minor%,%version_maintenance%,%version_revision%">>"%srcdir%\appversion.h" +) + +echo.>>"%srcdir%\appversion.h" +echo #define APP_VERSION_DATE %version_date%>>"%srcdir%\appversion.h" +echo #define APP_VERSION_DATE_STR "%version_date%">>"%srcdir%\appversion.h" +echo #define APP_VERSION_PDATE_STR "%version_pdate%">>"%srcdir%\appversion.h" +echo #define APP_VERSION_YMD_STR "%version_pdate_1%">>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo #define APP_COMMIT_AUTHOR "(%version_author_commit%)">>"%srcdir%\appversion.h" +echo #define APP_COMMIT_ID "%version_id_commit%">>"%srcdir%\appversion.h" +echo #define APP_COMMITS_URL "%url_commit%">>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" + +IF NOT "%version_specialbuild%" == "" ( + echo #define APP_VERSION_FLAGS VS_FF_SPECIALBUILD>>"%srcdir%\appversion.h" + echo #define APP_VERSION_SPECIALBUILD "%version_specialbuild%">>"%srcdir%\appversion.h" + echo #define APP_VERSION APP_VERSION_STRD "" APP_VERSION_SPECIALBUILD>>"%srcdir%\appversion.h" +) ELSE ( + echo #define APP_VERSION_FLAGS 0x0L>>"%srcdir%\appversion.h" + echo #define APP_VERSION APP_VERSION_STRD>>"%srcdir%\appversion.h" +) +echo.>>"%srcdir%\appversion.h" + +echo #endif //__APPVERSION_H__>>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" + +:: +:: Do update of version.cpp file last modify time to force it recompile +:: +copy /b "%srcdir%\version.cpp"+,, "%srcdir%\version.cpp" +endlocal + +:_exit +exit /B 0 \ No newline at end of file diff --git a/msvc/metamod.def b/metamod/msvc/metamod.def similarity index 75% rename from msvc/metamod.def rename to metamod/msvc/metamod.def index b62aafb..9e13bbf 100644 --- a/msvc/metamod.def +++ b/metamod/msvc/metamod.def @@ -1,4 +1,4 @@ -LIBRARY metamod +LIBRARY metamod_mm EXPORTS GiveFnptrsToDll @1 SECTIONS diff --git a/metamod/msvc/metamod.rc b/metamod/msvc/metamod.rc new file mode 100644 index 0000000..c8d5bdf --- /dev/null +++ b/metamod/msvc/metamod.rc @@ -0,0 +1,108 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "..\version\appversion.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +VS_VERSION_INFO VERSIONINFO +FILEVERSION APP_VERSION_C +PRODUCTVERSION APP_VERSION_C +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS (APP_VERSION_FLAGS | VS_FF_DEBUG) +#else + FILEFLAGS (APP_VERSION_FLAGS) +#endif +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041904b0" + BEGIN + VALUE "CompanyName", "" + VALUE "FileDescription", "Metamod Counter-Strike GameMod DLL" + VALUE "FileVersion", APP_VERSION_STRD_RC + VALUE "InternalName", "Metamod" + VALUE "LegalCopyright", "" + VALUE "OriginalFilename", "metamod_mm.dll" + VALUE "ProductName", "Metamod" + VALUE "ProductVersion", APP_VERSION_STRD_RC + #if APP_VERSION_FLAGS != 0x0L + VALUE "SpecialBuild", APP_VERSION_SPECIALBUILD + #endif + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x419, 1200 + END +END + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/metamod/msvc/metamod.vcxproj b/metamod/msvc/metamod.vcxproj new file mode 100644 index 0000000..e9af35a --- /dev/null +++ b/metamod/msvc/metamod.vcxproj @@ -0,0 +1,273 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {02832A39-E902-46B7-8D47-911C37CF41B0} + metamod + Win32Proj + + + + DynamicLibrary + v120_xp + MultiByte + true + + + DynamicLibrary + v120_xp + NotSet + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(ProjectName)_mm + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(ProjectName)_mm + + + + Disabled + $(ProjectDir)\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\version;$(ProjectDir)\..\include;$(ProjectDir)\..\include\common;$(ProjectDir)\..\include\dlls;$(ProjectDir)\..\include\engine;$(ProjectDir)\..\include\game_shared;$(ProjectDir)\..\include\pm_shared;$(ProjectDir)\..\include\public;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;METAMOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;__METAMOD_BUILD__;__BUILD_FAST_METAMOD__;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + Level3 + ProgramDatabase + + + metamod.def + true + Windows + MachineX86 + %(AdditionalDependencies) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + + + Setup version from Git revision + + + echo Empty Action + + + Force build to run Pre-Build event + + + + + $(ProjectDir)\..\;$(ProjectDir)\..\src;$(ProjectDir)\..\version;$(ProjectDir)\..\include;$(ProjectDir)\..\include\common;$(ProjectDir)\..\include\dlls;$(ProjectDir)\..\include\engine;$(ProjectDir)\..\include\game_shared;$(ProjectDir)\..\include\pm_shared;$(ProjectDir)\..\include\public;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;METAMOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;__METAMOD_BUILD__;__BUILD_FAST_METAMOD__;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + ProgramDatabase + Default + StreamingSIMDExtensions2 + + + true + Windows + true + true + MachineX86 + %(AdditionalDependencies) + + + echo Empty Action + + + Force build to run Pre-Build event + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + + + Automatic deployment script + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + + + Setup version from Git revision + + + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Create + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + Use + precompiled.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msvc/metamod.vcxproj.filters b/metamod/msvc/metamod.vcxproj.filters similarity index 70% rename from msvc/metamod.vcxproj.filters rename to metamod/msvc/metamod.vcxproj.filters index 110bd7a..85328ef 100644 --- a/msvc/metamod.vcxproj.filters +++ b/metamod/msvc/metamod.vcxproj.filters @@ -5,10 +5,6 @@ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav @@ -33,12 +29,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -75,9 +65,6 @@ Source Files - - Source Files - Source Files @@ -93,123 +80,119 @@ Source Files - + Source Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - + + Resource Files + - + Resource Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/metamod/msvc/reapi.rc b/metamod/msvc/reapi.rc new file mode 100644 index 0000000..bc666b3 --- /dev/null +++ b/metamod/msvc/reapi.rc @@ -0,0 +1,108 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "..\version\appversion.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +VS_VERSION_INFO VERSIONINFO +FILEVERSION APP_VERSION_C +PRODUCTVERSION APP_VERSION_C +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS (APP_VERSION_FLAGS | VS_FF_DEBUG) +#else + FILEFLAGS (APP_VERSION_FLAGS) +#endif +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "041904b0" + BEGIN + VALUE "CompanyName", "" + VALUE "FileDescription", "AMX Mod X module, using API regamedll & rehlds" + VALUE "FileVersion", APP_VERSION_STRD_RC + VALUE "InternalName", "Reapi" + VALUE "LegalCopyright", "" + VALUE "OriginalFilename", "reapi_amxx.dll" + VALUE "ProductName", "Reapi" + VALUE "ProductVersion", APP_VERSION_STRD_RC + #if APP_VERSION_FLAGS != 0x0L + VALUE "SpecialBuild", APP_VERSION_SPECIALBUILD + #endif + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x419, 1200 + END +END + +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/metamod/msvc/resource.h b/metamod/msvc/resource.h new file mode 100644 index 0000000..7c3f681 --- /dev/null +++ b/metamod/msvc/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ReVoice.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/metamod/msvc/test.bat b/metamod/msvc/test.bat new file mode 100644 index 0000000..fb2500f --- /dev/null +++ b/metamod/msvc/test.bat @@ -0,0 +1,65 @@ +@setlocal enableextensions enabledelayedexpansion +@echo off + +set repodir="D:\GitHub\metamod\metamod" +set url_commit= +set branch_remote=origin + +:: Get remote url +FOR /F "tokens=2 delims=@" %%i IN ('git -C D:\GitHub\metamod\metamod config remote.origin.url') DO ( + set url_commit=%%i +) + + +set source_string1=git@github.com:s1lentq/metamod.git +set source_string2=https://github.com/s1lentq/metamod.git + + +If NOT "%source_string1%"=="%source_string1:bitbucket.org=%" ( + echo source_string1 = ECTb! +) ELSE ( + echo source_string1 = HETY! +) + + +If NOT "%source_string2%"=="%source_string2:bitbucket.org=%" ( + echo source_string2 = ECTb! +) ELSE ( + echo source_string2 = HETY! +) + + + +IF [!url_commit!] == [] ( + FOR /F "tokens=1" %%i IN ('"git -C "%repodir%\." config remote.!branch_remote!.url"') DO ( + set url_commit=%%i + ) + + :: strip .git + if "x!url_commit:~-4!"=="x.git" ( + set url_commit=!url_commit:~0,-4! + ) + :: append extra string + set url_commit=!url_commit!/commit/ +) ELSE ( + :: strip .git + if "x!url_commit:~-4!"=="x.git" ( + set url_commit=!url_commit:~0,-4! + ) + :: replace : to / + set url_commit=!url_commit::=/! + :: append extra string + set url_commit=https://!url_commit!/commit/ +) + + + + + +::echo Url: = "%url_commit%" + + +::D:\GitHub\metamod>git -C D:\GitHub\metamod\metamod config remote.origin.url +::https://bitbucket.org/rehlds/metamod + +pause \ No newline at end of file diff --git a/src/api_hook.cpp b/metamod/src/api_hook.cpp similarity index 58% rename from src/api_hook.cpp rename to metamod/src/api_hook.cpp index aa7eb15..4d658a0 100644 --- a/src/api_hook.cpp +++ b/metamod/src/api_hook.cpp @@ -1,12 +1,4 @@ -#include // offsetof -#include -#include "ret_type.h" -#include "types_meta.h" -#include "api_info.h" -#include "api_hook.h" -#include "mplugin.h" -#include "metamod.h" -#include "osdep.h" //unlikely +#include "precompiled.h" // getting pointer with table index is faster than with if-else static const void ** api_tables[3] = { @@ -22,27 +14,28 @@ static const void ** api_info_tables[3] = { }; // Safety check for metamod-bot-plugin bugfix. -// engine_api->pfnRunPlayerMove calls dllapi-functions before it returns. -// This causes problems with bots running as metamod plugins, because -// metamod assumed that PublicMetaGlobals is free to be used. -// With call_count we can fix this by backuping up PublicMetaGlobals if -// it's already being used. +// engine_api->pfnRunPlayerMove calls dllapi-functions before it returns. +// This causes problems with bots running as metamod plugins, because +// metamod assumed that PublicMetaGlobals is free to be used. +// With call_count we can fix this by backuping up PublicMetaGlobals if +// it's already being used. static unsigned int call_count = 0; // get function pointer from api table by function pointer offset -inline void * DLLINTERNAL get_api_function(const void * api_table, unsigned int func_offset) +inline void *get_api_function(const void * api_table, unsigned int func_offset) { - return(*(void**)((unsigned long)api_table + func_offset)); + return *(void**)((unsigned long)api_table + func_offset); } // get data pointer from api_info table by function offset -inline const api_info_t * DLLINTERNAL get_api_info(enum_api_t api, unsigned int api_info_offset) +inline const api_info_t *get_api_info(enum_api_t api, unsigned int api_info_offset) { - return((const api_info_t *)((unsigned long)api_info_tables[api] + api_info_offset)); + return (const api_info_t *)((unsigned long)api_info_tables[api] + api_info_offset); } // simplified 'void' version of main hook function -void DLLINTERNAL main_hook_function_void(unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args) { +void main_hook_function_void(unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void *packed_args) +{ const api_info_t *api_info; int i; META_RES mres, status, prev_mres; @@ -51,15 +44,16 @@ void DLLINTERNAL main_hook_function_void(unsigned int api_info_offset, enum_api_ int loglevel; const void *api_table; meta_globals_t backup_meta_globals[1]; - //passing offset from api wrapper function makes code faster/smaller + // passing offset from api wrapper function makes code faster/smaller api_info = get_api_info(api, api_info_offset); - //Fix bug with metamod-bot-plugins. - if(unlikely(call_count++>0)) + + // Fix bug with metamod-bot-plugins. + if (call_count++ > 0) { //Backup PublicMetaGlobals. backup_meta_globals[0] = PublicMetaGlobals; } - //Setup + // Setup loglevel=api_info->loglevel; mres=MRES_UNSET; status=MRES_UNSET; @@ -67,19 +61,20 @@ void DLLINTERNAL main_hook_function_void(unsigned int api_info_offset, enum_api_ pfn_routine=NULL; //Pre plugin functions prev_mres=MRES_UNSET; - for(i=0; likely(i < Plugins->endlist); i++) + for (i = 0; i < Plugins->endlist; i++) { iplug=&Plugins->plist[i]; - if(unlikely(iplug->status != PL_RUNNING)) + if (iplug->status != PL_RUNNING) continue; + api_table = iplug->get_api_table(api); - if(likely(!api_table)) + if (!api_table) { //plugin doesn't provide this api table continue; } pfn_routine=get_api_function(api_table, func_offset); - if(likely(!pfn_routine)) + if (!pfn_routine) { //plugin doesn't provide this function continue; @@ -94,95 +89,96 @@ void DLLINTERNAL main_hook_function_void(unsigned int api_info_offset, enum_api_ API_UNPAUSE_TSC_TRACKING(); // plugin's result code mres=PublicMetaGlobals.mres; - if(unlikely(mres > status)) + if (mres > status) status = mres; // save this for successive plugins to see prev_mres = mres; - if(unlikely(mres==MRES_UNSET)) + if (mres==MRES_UNSET) META_WARNING("Plugin didn't set meta_result: %s:%s()", iplug->file, api_info->name); } call_count--; //Api call - if(likely(status!=MRES_SUPERCEDE)) + if (status != MRES_SUPERCEDE) { //get api table api_table = *api_tables[api]; - - if(likely(api_table)) { + + if (api_table) + { pfn_routine = get_api_function(api_table, func_offset); - if(likely(pfn_routine)) { + if (pfn_routine) { META_DEBUG(loglevel, ("Calling %s:%s()", (api==e_api_engine)?"engine":GameDLL.file, api_info->name)); api_info->api_caller(pfn_routine, packed_args); API_UNPAUSE_TSC_TRACKING(); } else { // don't complain for NULL routines in NEW_DLL_FUNCTIONS - if(unlikely(api != e_api_newapi)) + if (api != e_api_newapi) META_WARNING("Couldn't find api call: %s:%s", (api==e_api_engine)?"engine":GameDLL.file, api_info->name); status=MRES_UNSET; } } else { // don't complain for NULL NEW_DLL_FUNCTIONS-table - if(unlikely(api != e_api_newapi)) + if (api != e_api_newapi) META_DEBUG(loglevel, ("No api table defined for api call: %s:%s", (api==e_api_engine)?"engine":GameDLL.file, api_info->name)); status=MRES_UNSET; } } else META_DEBUG(loglevel, ("Skipped (supercede) %s:%s()", (api==e_api_engine)?"engine":GameDLL.file, api_info->name)); - + call_count++; - + //Post plugin functions prev_mres=MRES_UNSET; - for(i=0; likely(i < Plugins->endlist); i++) { + for (i=0; i < Plugins->endlist; i++) { iplug=&Plugins->plist[i]; - - if(unlikely(iplug->status != PL_RUNNING)) + + if (iplug->status != PL_RUNNING) continue; - + api_table = iplug->get_api_post_table(api); - if(likely(!api_table)) { + if (!api_table) { //plugin doesn't provide this api table continue; } - + pfn_routine=get_api_function(api_table, func_offset); - if(likely(!pfn_routine)) { + if (!pfn_routine) { //plugin doesn't provide this function continue; } - + // initialize PublicMetaGlobals PublicMetaGlobals.mres = MRES_UNSET; PublicMetaGlobals.prev_mres = prev_mres; PublicMetaGlobals.status = status; - + // call plugin META_DEBUG(loglevel, ("Calling %s:%s_Post()", iplug->file, api_info->name)); api_info->api_caller(pfn_routine, packed_args); API_UNPAUSE_TSC_TRACKING(); - + // plugin's result code mres=PublicMetaGlobals.mres; - if(unlikely(mres > status)) + if (mres > status) status = mres; - + // save this for successive plugins to see prev_mres = mres; - - if(unlikely(mres==MRES_UNSET)) + + if (mres==MRES_UNSET) META_WARNING("Plugin didn't set meta_result: %s:%s_Post()", iplug->file, api_info->name); - else if(unlikely(mres==MRES_SUPERCEDE)) + else if (mres==MRES_SUPERCEDE) META_WARNING("MRES_SUPERCEDE not valid in Post functions: %s:%s_Post()", iplug->file, api_info->name); } - if(unlikely(--call_count>0)) { + if (--call_count>0) { //Restore backup PublicMetaGlobals = backup_meta_globals[0]; } } // full return typed version of main hook function -void * DLLINTERNAL main_hook_function(const class_ret_t ret_init, unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args) { +void *main_hook_function(const class_ret_t ret_init, unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args) { const api_info_t *api_info; int i; META_RES mres, status, prev_mres; @@ -191,106 +187,106 @@ void * DLLINTERNAL main_hook_function(const class_ret_t ret_init, unsigned int a int loglevel; const void *api_table; meta_globals_t backup_meta_globals[1]; - + //passing offset from api wrapper function makes code faster/smaller api_info = get_api_info(api, api_info_offset); - + //Fix bug with metamod-bot-plugins. - if(unlikely(call_count++>0)) { + if (call_count++>0) { //Backup PublicMetaGlobals. backup_meta_globals[0] = PublicMetaGlobals; } - + //Return class setup class_ret_t dllret=ret_init; class_ret_t override_ret=ret_init; class_ret_t pub_override_ret=ret_init; class_ret_t orig_ret=ret_init; class_ret_t pub_orig_ret=ret_init; - + //Setup loglevel=api_info->loglevel; mres=MRES_UNSET; status=MRES_UNSET; prev_mres=MRES_UNSET; pfn_routine=NULL; - + //Pre plugin functions prev_mres=MRES_UNSET; - for(i=0; likely(i < Plugins->endlist); i++) { + for (i=0; i < Plugins->endlist; i++) { iplug=&Plugins->plist[i]; - - if(unlikely(iplug->status != PL_RUNNING)) + + if (iplug->status != PL_RUNNING) continue; - + api_table = iplug->get_api_table(api); - if(likely(!api_table)) { + if (!api_table) { //plugin doesn't provide this api table continue; } - + pfn_routine=get_api_function(api_table, func_offset); - if(likely(!pfn_routine)) { + if (!pfn_routine) { //plugin doesn't provide this function continue; } - + // initialize PublicMetaGlobals PublicMetaGlobals.mres = MRES_UNSET; PublicMetaGlobals.prev_mres = prev_mres; PublicMetaGlobals.status = status; pub_orig_ret = orig_ret; PublicMetaGlobals.orig_ret = pub_orig_ret.getptr(); - if(unlikely(status==MRES_SUPERCEDE)) { + if (status==MRES_SUPERCEDE) { pub_override_ret = override_ret; PublicMetaGlobals.override_ret = pub_override_ret.getptr(); } - + // call plugin META_DEBUG(loglevel, ("Calling %s:%s()", iplug->file, api_info->name)); dllret = class_ret_t(api_info->api_caller(pfn_routine, packed_args)); API_UNPAUSE_TSC_TRACKING(); - + // plugin's result code mres=PublicMetaGlobals.mres; - if(unlikely(mres > status)) + if (mres > status) status = mres; - + // save this for successive plugins to see prev_mres = mres; - - if(unlikely(mres==MRES_SUPERCEDE)) { + + if (mres==MRES_SUPERCEDE) { pub_override_ret = dllret; override_ret = dllret; - } - else if(unlikely(mres==MRES_UNSET)) { + } + else if (mres==MRES_UNSET) { META_WARNING("Plugin didn't set meta_result: %s:%s()", iplug->file, api_info->name); } } - + call_count--; - + //Api call - if(likely(status!=MRES_SUPERCEDE)) { + if (status != MRES_SUPERCEDE) { //get api table api_table = *api_tables[api]; - - if(likely(api_table)) { + + if (api_table) { pfn_routine = get_api_function(api_table, func_offset); - if(likely(pfn_routine)) { + if (pfn_routine) { META_DEBUG(loglevel, ("Calling %s:%s()", (api==e_api_engine)?"engine":GameDLL.file, api_info->name)); dllret = class_ret_t(api_info->api_caller(pfn_routine, packed_args)); API_UNPAUSE_TSC_TRACKING(); orig_ret = dllret; } else { // don't complain for NULL routines in NEW_DLL_FUNCTIONS - if(unlikely(api != e_api_newapi)) + if (api != e_api_newapi) META_WARNING("Couldn't find api call: %s:%s", (api==e_api_engine)?"engine":GameDLL.file, api_info->name); status=MRES_UNSET; } } else { // don't complain for NULL NEW_DLL_FUNCTIONS-table - if(unlikely(api != e_api_newapi)) + if (api != e_api_newapi) META_DEBUG(loglevel, ("No api table defined for api call: %s:%s", (api==e_api_engine)?"engine":GameDLL.file, api_info->name)); status=MRES_UNSET; } @@ -300,352 +296,348 @@ void * DLLINTERNAL main_hook_function(const class_ret_t ret_init, unsigned int a pub_orig_ret = override_ret; PublicMetaGlobals.orig_ret = pub_orig_ret.getptr(); } - + call_count++; - + //Pre plugin functions prev_mres=MRES_UNSET; - for(i=0; likely(i < Plugins->endlist); i++) { + for (i=0; i < Plugins->endlist; i++) { iplug=&Plugins->plist[i]; - - if(unlikely(iplug->status != PL_RUNNING)) + + if (iplug->status != PL_RUNNING) continue; - + api_table = iplug->get_api_post_table(api); - if(likely(!api_table)) { + if (!api_table) { //plugin doesn't provide this api table continue; } - + pfn_routine=get_api_function(api_table, func_offset); - if(likely(!pfn_routine)) { + if (!pfn_routine) { //plugin doesn't provide this function continue; } - + // initialize PublicMetaGlobals PublicMetaGlobals.mres = MRES_UNSET; PublicMetaGlobals.prev_mres = prev_mres; PublicMetaGlobals.status = status; pub_orig_ret = orig_ret; PublicMetaGlobals.orig_ret = pub_orig_ret.getptr(); - if(unlikely(status==MRES_OVERRIDE)) { + if (status==MRES_OVERRIDE) { pub_override_ret = override_ret; PublicMetaGlobals.override_ret = pub_override_ret.getptr(); } - + // call plugin META_DEBUG(loglevel, ("Calling %s:%s_Post()", iplug->file, api_info->name)); dllret = class_ret_t(api_info->api_caller(pfn_routine, packed_args)); API_UNPAUSE_TSC_TRACKING(); - + // plugin's result code mres=PublicMetaGlobals.mres; - if(unlikely(mres > status)) + if (mres > status) status = mres; - + // save this for successive plugins to see prev_mres = mres; - - if(unlikely(mres==MRES_OVERRIDE)) { + + if (mres==MRES_OVERRIDE) { pub_override_ret = dllret; override_ret = dllret; } - else if(unlikely(mres==MRES_UNSET)) { + else if (mres==MRES_UNSET) { META_WARNING("Plugin didn't set meta_result: %s:%s_Post()", iplug->file, api_info->name); } - else if(unlikely(mres==MRES_SUPERCEDE)) { + else if (mres==MRES_SUPERCEDE) { META_WARNING("MRES_SUPERCEDE not valid in Post functions: %s:%s_Post()", iplug->file, api_info->name); } } - - if(unlikely(--call_count>0)) { + + if (--call_count>0) { //Restore backup PublicMetaGlobals = backup_meta_globals[0]; } - - //return value is passed through ret_init! - if(likely(status!=MRES_OVERRIDE)) { - return(*(void**)orig_ret.getptr()); + + // return value is passed through ret_init! + if (status != MRES_OVERRIDE) { + return *(void**)orig_ret.getptr(); } else { META_DEBUG(loglevel, ("Returning (override) %s()", api_info->name)); - return(*(void**)override_ret.getptr()); + return *(void**)override_ret.getptr(); } } -// // Macros for creating api caller functions -// #define BEGIN_API_CALLER_FUNC(ret_type, args_type_code) \ - void * DLLINTERNAL _COMBINE4(api_caller_, ret_type, _args_, args_type_code)(const void * func, const void * packed_args) { \ + void *_COMBINE4(api_caller_, ret_type, _args_, args_type_code)(const void * func, const void * packed_args) { \ _COMBINE2(pack_args_type_, args_type_code) * p ATTRIBUTE(unused)= (_COMBINE2(pack_args_type_, args_type_code) *)packed_args; #define END_API_CALLER_FUNC(ret_t, args_t, args) \ API_PAUSE_TSC_TRACKING(); \ - return(*(void **)class_ret_t((*(( ret_t (*) args_t )func)) args).getptr()); \ + return *(void **)class_ret_t((*((ret_t (*) args_t)func)) args).getptr(); \ } #define END_API_CALLER_FUNC_void(args_t, args) \ API_PAUSE_TSC_TRACKING(); \ - return((*(( void* (*) args_t )func)) args); \ + return (*((void* (*) args_t)func)) args; \ } -// // API function callers. -// //- BEGIN_API_CALLER_FUNC(void, ipV) -END_API_CALLER_FUNC_void( (int, const void*, ...), (p->i1, p->p1, p->str) ) +END_API_CALLER_FUNC_void((int, const void*, ...), (p->i1, p->p1, p->str)) //- BEGIN_API_CALLER_FUNC(void, 2pV) -END_API_CALLER_FUNC_void( (const void*, const void*, ...), (p->p1, p->p2, p->str) ) +END_API_CALLER_FUNC_void((const void*, const void*, ...), (p->p1, p->p2, p->str)) //- BEGIN_API_CALLER_FUNC(void, void) -END_API_CALLER_FUNC_void( (void), () ) +END_API_CALLER_FUNC_void((), ()) BEGIN_API_CALLER_FUNC(ptr, void) -END_API_CALLER_FUNC(void*, (void), () ) +END_API_CALLER_FUNC(void*, (), ()) BEGIN_API_CALLER_FUNC(int, void) -END_API_CALLER_FUNC(int, (void), () ) +END_API_CALLER_FUNC(int, (), ()) BEGIN_API_CALLER_FUNC(float, void) -END_API_CALLER_FUNC(float, (void), () ) +END_API_CALLER_FUNC(float, (), ()) //- BEGIN_API_CALLER_FUNC(float, 2f) -END_API_CALLER_FUNC( float, (float, float), (p->f1, p->f2) ) +END_API_CALLER_FUNC(float, (float, float), (p->f1, p->f2)) //- BEGIN_API_CALLER_FUNC(void, 2i) -END_API_CALLER_FUNC_void( (int, int), (p->i1, p->i2) ); +END_API_CALLER_FUNC_void((int, int), (p->i1, p->i2)); BEGIN_API_CALLER_FUNC(int, 2i) -END_API_CALLER_FUNC(int, (int, int), (p->i1, p->i2) ); +END_API_CALLER_FUNC(int, (int, int), (p->i1, p->i2)); //- BEGIN_API_CALLER_FUNC(void, 2i2p) -END_API_CALLER_FUNC_void( (int, int, const void*, const void*), (p->i1, p->i2, p->p1, p->p2) ); +END_API_CALLER_FUNC_void((int, int, const void*, const void*), (p->i1, p->i2, p->p1, p->p2)); //- BEGIN_API_CALLER_FUNC(void, 2i2pi2p) -END_API_CALLER_FUNC_void( (int, int, const void*, const void*, int, const void*, const void*), (p->i1, p->i2, p->p1, p->p2, p->i3, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((int, int, const void*, const void*, int, const void*, const void*), (p->i1, p->i2, p->p1, p->p2, p->i3, p->p3, p->p4)); //- BEGIN_API_CALLER_FUNC(void, 2p) -END_API_CALLER_FUNC_void( (const void*, const void*), (p->p1, p->p2) ); +END_API_CALLER_FUNC_void((const void*, const void*), (p->p1, p->p2)); BEGIN_API_CALLER_FUNC(ptr, 2p) -END_API_CALLER_FUNC(void*, (const void*, const void*), (p->p1, p->p2) ); +END_API_CALLER_FUNC(void*, (const void*, const void*), (p->p1, p->p2)); BEGIN_API_CALLER_FUNC(int, 2p) -END_API_CALLER_FUNC(int, (const void*, const void*), (p->p1, p->p2) ); +END_API_CALLER_FUNC(int, (const void*, const void*), (p->p1, p->p2)); //- BEGIN_API_CALLER_FUNC(void, 2p2f) -END_API_CALLER_FUNC_void( (const void*, const void*, float, float), (p->p1, p->p2, p->f1, p->f2) ); +END_API_CALLER_FUNC_void((const void*, const void*, float, float), (p->p1, p->p2, p->f1, p->f2)); //- BEGIN_API_CALLER_FUNC(void, 2p2i2p) -END_API_CALLER_FUNC_void( (const void*, const void*, int, int, const void*, const void*), (p->p1, p->p2, p->i1, p->i2, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((const void*, const void*, int, int, const void*, const void*), (p->p1, p->p2, p->i1, p->i2, p->p3, p->p4)); //- BEGIN_API_CALLER_FUNC(void, 2p3fus2uc) -END_API_CALLER_FUNC_void( (const void*, const void*, float, float, float, unsigned short, unsigned char, unsigned char), (p->p1, p->p2, p->f1, p->f2, p->f3, p->us1, p->uc1, p->uc2) ); +END_API_CALLER_FUNC_void((const void*, const void*, float, float, float, unsigned short, unsigned char, unsigned char), (p->p1, p->p2, p->f1, p->f2, p->f3, p->us1, p->uc1, p->uc2)); //- BEGIN_API_CALLER_FUNC(ptr, 2pf) -END_API_CALLER_FUNC(void*, (const void*, const void*, float), (p->p1, p->p2, p->f1) ); +END_API_CALLER_FUNC(void*, (const void*, const void*, float), (p->p1, p->p2, p->f1)); //- BEGIN_API_CALLER_FUNC(void, 2pfi) -END_API_CALLER_FUNC_void( (const void*, const void*, float, int), (p->p1, p->p2, p->f1, p->i1) ); +END_API_CALLER_FUNC_void((const void*, const void*, float, int), (p->p1, p->p2, p->f1, p->i1)); //- BEGIN_API_CALLER_FUNC(void, 2pi) -END_API_CALLER_FUNC_void( (const void*, const void*, int), (p->p1, p->p2, p->i1) ); +END_API_CALLER_FUNC_void((const void*, const void*, int), (p->p1, p->p2, p->i1)); BEGIN_API_CALLER_FUNC(int, 2pi) -END_API_CALLER_FUNC(int, (const void*, const void*, int), (p->p1, p->p2, p->i1) ); +END_API_CALLER_FUNC(int, (const void*, const void*, int), (p->p1, p->p2, p->i1)); //- BEGIN_API_CALLER_FUNC(void, 2pui) -END_API_CALLER_FUNC_void( (const void*, const void*, unsigned int), (p->p1, p->p2, p->ui1) ); +END_API_CALLER_FUNC_void((const void*, const void*, unsigned int), (p->p1, p->p2, p->ui1)); //- BEGIN_API_CALLER_FUNC(void, 2pi2p) -END_API_CALLER_FUNC_void( (const void*, const void*, int, const void*, const void*), (p->p1, p->p2, p->i1, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((const void*, const void*, int, const void*, const void*), (p->p1, p->p2, p->i1, p->p3, p->p4)); //- BEGIN_API_CALLER_FUNC(void, 2pif2p) -END_API_CALLER_FUNC_void( (const void*, const void*, int, float, const void*, const void*), (p->p1, p->p2, p->i1, p->f1, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((const void*, const void*, int, float, const void*, const void*), (p->p1, p->p2, p->i1, p->f1, p->p3, p->p4)); //- BEGIN_API_CALLER_FUNC(int, 3i) -END_API_CALLER_FUNC(int, (int, int, int), (p->i1, p->i2, p->i3) ); +END_API_CALLER_FUNC(int, (int, int, int), (p->i1, p->i2, p->i3)); //- BEGIN_API_CALLER_FUNC(void, 3p) -END_API_CALLER_FUNC_void( (const void*, const void*, const void*), (p->p1, p->p2, p->p3) ); +END_API_CALLER_FUNC_void((const void*, const void*, const void*), (p->p1, p->p2, p->p3)); BEGIN_API_CALLER_FUNC(ptr, 3p) -END_API_CALLER_FUNC(void*, (const void*, const void*, const void*), (p->p1, p->p2, p->p3) ); +END_API_CALLER_FUNC(void*, (const void*, const void*, const void*), (p->p1, p->p2, p->p3)); BEGIN_API_CALLER_FUNC(int, 3p) -END_API_CALLER_FUNC(int, (const void*, const void*, const void*), (p->p1, p->p2, p->p3) ); +END_API_CALLER_FUNC(int, (const void*, const void*, const void*), (p->p1, p->p2, p->p3)); //- BEGIN_API_CALLER_FUNC(void, 3p2f2i) -END_API_CALLER_FUNC_void( (const void*, const void*, const void*, float, float, int, int), (p->p1, p->p2, p->p3, p->f1, p->f2, p->i1, p->i2) ); +END_API_CALLER_FUNC_void((const void*, const void*, const void*, float, float, int, int), (p->p1, p->p2, p->p3, p->f1, p->f2, p->i1, p->i2)); //- BEGIN_API_CALLER_FUNC(int, 3pi2p) -END_API_CALLER_FUNC(int, (const void*, const void*, const void*, int, const void*, const void*), (p->p1, p->p2, p->p3, p->i1, p->p4, p->p5) ); +END_API_CALLER_FUNC(int, (const void*, const void*, const void*, int, const void*, const void*), (p->p1, p->p2, p->p3, p->i1, p->p4, p->p5)); //- BEGIN_API_CALLER_FUNC(void, 4p) -END_API_CALLER_FUNC_void( (const void*, const void*, const void*, const void*), (p->p1, p->p2, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((const void*, const void*, const void*, const void*), (p->p1, p->p2, p->p3, p->p4)); BEGIN_API_CALLER_FUNC(int, 4p) -END_API_CALLER_FUNC(int, (const void*, const void*, const void*, const void*), (p->p1, p->p2, p->p3, p->p4) ); +END_API_CALLER_FUNC(int, (const void*, const void*, const void*, const void*), (p->p1, p->p2, p->p3, p->p4)); //- BEGIN_API_CALLER_FUNC(void, 4pi) -END_API_CALLER_FUNC_void( (const void*, const void*, const void*, const void*, int), (p->p1, p->p2, p->p3, p->p4, p->i1) ); +END_API_CALLER_FUNC_void((const void*, const void*, const void*, const void*, int), (p->p1, p->p2, p->p3, p->p4, p->i1)); BEGIN_API_CALLER_FUNC(int, 4pi) -END_API_CALLER_FUNC(int, (const void*, const void*, const void*, const void*, int), (p->p1, p->p2, p->p3, p->p4, p->i1) ); +END_API_CALLER_FUNC(int, (const void*, const void*, const void*, const void*, int), (p->p1, p->p2, p->p3, p->p4, p->i1)); //- BEGIN_API_CALLER_FUNC(void, f) -END_API_CALLER_FUNC_void( (float), (p->f1) ); +END_API_CALLER_FUNC_void((float), (p->f1)); //- BEGIN_API_CALLER_FUNC(void, i) -END_API_CALLER_FUNC_void( (int), (p->i1) ); +END_API_CALLER_FUNC_void((int), (p->i1)); BEGIN_API_CALLER_FUNC(int, i) -END_API_CALLER_FUNC(int, (int), (p->i1) ); +END_API_CALLER_FUNC(int, (int), (p->i1)); BEGIN_API_CALLER_FUNC(ptr, i) -END_API_CALLER_FUNC(void*, (int), (p->i1) ); +END_API_CALLER_FUNC(void*, (int), (p->i1)); BEGIN_API_CALLER_FUNC(uint, ui) -END_API_CALLER_FUNC(unsigned int, (unsigned int), (p->ui1) ); +END_API_CALLER_FUNC(unsigned int, (unsigned int), (p->ui1)); BEGIN_API_CALLER_FUNC(ptr, ui) -END_API_CALLER_FUNC(void*, (unsigned int), (p->ui1) ); +END_API_CALLER_FUNC(void*, (unsigned int), (p->ui1)); //- BEGIN_API_CALLER_FUNC(ulong, ul) -END_API_CALLER_FUNC(unsigned long, (unsigned long), (p->ul1) ); +END_API_CALLER_FUNC(unsigned long, (unsigned long), (p->ul1)); //- BEGIN_API_CALLER_FUNC(void, i2p) -END_API_CALLER_FUNC_void( (int, const void*, const void*), (p->i1, p->p1, p->p2) ); +END_API_CALLER_FUNC_void((int, const void*, const void*), (p->i1, p->p1, p->p2)); BEGIN_API_CALLER_FUNC(int, i2p) -END_API_CALLER_FUNC(int, (int, const void*, const void*), (p->i1, p->p1, p->p2) ); +END_API_CALLER_FUNC(int, (int, const void*, const void*), (p->i1, p->p1, p->p2)); //- BEGIN_API_CALLER_FUNC(void, i3p) -END_API_CALLER_FUNC_void( (int, const void*, const void*, const void*), (p->i1, p->p1, p->p2, p->p3) ); +END_API_CALLER_FUNC_void((int, const void*, const void*, const void*), (p->i1, p->p1, p->p2, p->p3)); //- BEGIN_API_CALLER_FUNC(void, ip) -END_API_CALLER_FUNC_void( (int, const void*), (p->i1, p->p1) ); +END_API_CALLER_FUNC_void((int, const void*), (p->i1, p->p1)); BEGIN_API_CALLER_FUNC(ushort, ip) -END_API_CALLER_FUNC( unsigned short, (int, const void*), (p->i1, p->p1) ); +END_API_CALLER_FUNC(unsigned short, (int, const void*), (p->i1, p->p1)); BEGIN_API_CALLER_FUNC(int, ip) -END_API_CALLER_FUNC( int, (int, const void*), (p->i1, p->p1) ); +END_API_CALLER_FUNC(int, (int, const void*), (p->i1, p->p1)); //- BEGIN_API_CALLER_FUNC(void, ipusf2p2f4i) -END_API_CALLER_FUNC_void( (int, const void*, unsigned short, float, const void*, const void*, float, float, int, int, int, int), (p->i1, p->p1, p->us1, p->f1, p->p2, p->p3, p->f2, p->f3, p->i2, p->i3, p->i4, p->i5) ); +END_API_CALLER_FUNC_void((int, const void*, unsigned short, float, const void*, const void*, float, float, int, int, int, int), (p->i1, p->p1, p->us1, p->f1, p->p2, p->p3, p->f2, p->f3, p->i2, p->i3, p->i4, p->i5)); //- BEGIN_API_CALLER_FUNC(void, p) -END_API_CALLER_FUNC_void( (const void*), (p->p1) ); +END_API_CALLER_FUNC_void((const void*), (p->p1)); BEGIN_API_CALLER_FUNC(ptr, p) -END_API_CALLER_FUNC(void*, (const void*), (p->p1) ); +END_API_CALLER_FUNC(void*, (const void*), (p->p1)); BEGIN_API_CALLER_FUNC(char, p) -END_API_CALLER_FUNC(char, (const void*), (p->p1) ); +END_API_CALLER_FUNC(char, (const void*), (p->p1)); BEGIN_API_CALLER_FUNC(int, p) -END_API_CALLER_FUNC(int, (const void*), (p->p1) ); +END_API_CALLER_FUNC(int, (const void*), (p->p1)); BEGIN_API_CALLER_FUNC(uint, p) -END_API_CALLER_FUNC(unsigned int, (const void*), (p->p1) ); +END_API_CALLER_FUNC(unsigned int, (const void*), (p->p1)); BEGIN_API_CALLER_FUNC(float, p) -END_API_CALLER_FUNC(float, (const void*), (p->p1) ); +END_API_CALLER_FUNC(float, (const void*), (p->p1)); //- BEGIN_API_CALLER_FUNC(void, p2f) -END_API_CALLER_FUNC_void( (const void*, float, float), (p->p1, p->f1, p->f2) ); +END_API_CALLER_FUNC_void((const void*, float, float), (p->p1, p->f1, p->f2)); //- BEGIN_API_CALLER_FUNC(int, p2fi) -END_API_CALLER_FUNC(int, (const void*, float, float, int), (p->p1, p->f1, p->f2, p->i1) ); +END_API_CALLER_FUNC(int, (const void*, float, float, int), (p->p1, p->f1, p->f2, p->i1)); //- BEGIN_API_CALLER_FUNC(void, p2i) -END_API_CALLER_FUNC_void( (const void*, int, int), (p->p1, p->i1, p->i2) ); +END_API_CALLER_FUNC_void((const void*, int, int), (p->p1, p->i1, p->i2)); //- BEGIN_API_CALLER_FUNC(void, p3i) -END_API_CALLER_FUNC_void( (const void*, int, int, int), (p->p1, p->i1, p->i2, p->i3) ); +END_API_CALLER_FUNC_void((const void*, int, int, int), (p->p1, p->i1, p->i2, p->i3)); //- BEGIN_API_CALLER_FUNC(void, p4i) -END_API_CALLER_FUNC_void( (const void*, int, int, int, int), (p->p1, p->i1, p->i2, p->i3, p->i4) ); +END_API_CALLER_FUNC_void((const void*, int, int, int, int), (p->p1, p->i1, p->i2, p->i3, p->i4)); //- BEGIN_API_CALLER_FUNC(void, puc) -END_API_CALLER_FUNC_void( (const void*, unsigned char), (p->p1, p->uc1) ); +END_API_CALLER_FUNC_void((const void*, unsigned char), (p->p1, p->uc1)); //- BEGIN_API_CALLER_FUNC(void, pf) -END_API_CALLER_FUNC_void( (const void*, float), (p->p1, p->f1) ); +END_API_CALLER_FUNC_void((const void*, float), (p->p1, p->f1)); //- BEGIN_API_CALLER_FUNC(void, pfp) -END_API_CALLER_FUNC_void( (const void*, float, const void*), (p->p1, p->f1, p->p2) ); +END_API_CALLER_FUNC_void((const void*, float, const void*), (p->p1, p->f1, p->p2)); //- BEGIN_API_CALLER_FUNC(void, pi) -END_API_CALLER_FUNC_void( (const void*, int), (p->p1, p->i1) ); +END_API_CALLER_FUNC_void((const void*, int), (p->p1, p->i1)); BEGIN_API_CALLER_FUNC(ptr, pi) -END_API_CALLER_FUNC(void*, (const void*, int), (p->p1, p->i1) ); +END_API_CALLER_FUNC(void*, (const void*, int), (p->p1, p->i1)); BEGIN_API_CALLER_FUNC(int, pi) -END_API_CALLER_FUNC(int, (const void*, int), (p->p1, p->i1) ); +END_API_CALLER_FUNC(int, (const void*, int), (p->p1, p->i1)); //- BEGIN_API_CALLER_FUNC(void, pi2p) -END_API_CALLER_FUNC_void( (const void*, int, const void*, const void*), (p->p1, p->i1, p->p2, p->p3) ); +END_API_CALLER_FUNC_void((const void*, int, const void*, const void*), (p->p1, p->i1, p->p2, p->p3)); //- BEGIN_API_CALLER_FUNC(int, pi2p2ip) -END_API_CALLER_FUNC(int, (const void*, int, const void*, const void*, int, int, const void*), (p->p1, p->i1, p->p2, p->p3, p->i2, p->i3, p->p4) ); +END_API_CALLER_FUNC(int, (const void*, int, const void*, const void*, int, int, const void*), (p->p1, p->i1, p->p2, p->p3, p->i2, p->i3, p->p4)); //- BEGIN_API_CALLER_FUNC(void, pip) -END_API_CALLER_FUNC_void( (const void*, int, const void*), (p->p1, p->i1, p->p2) ); +END_API_CALLER_FUNC_void((const void*, int, const void*), (p->p1, p->i1, p->p2)); BEGIN_API_CALLER_FUNC(ptr, pip) -END_API_CALLER_FUNC(void*, (const void*, int, const void*), (p->p1, p->i1, p->p2) ); +END_API_CALLER_FUNC(void*, (const void*, int, const void*), (p->p1, p->i1, p->p2)); //- BEGIN_API_CALLER_FUNC(void, pip2f2i) -END_API_CALLER_FUNC_void( (const void*, int, const void*, float, float, int, int), (p->p1, p->i1, p->p2, p->f1, p->f2, p->i2, p->i3) ); +END_API_CALLER_FUNC_void((const void*, int, const void*, float, float, int, int), (p->p1, p->i1, p->p2, p->f1, p->f2, p->i2, p->i3)); //- BEGIN_API_CALLER_FUNC(void, pip2f4i2p) -END_API_CALLER_FUNC_void( (const void*, int, const void*, float, float, int, int, int, int, const void*, const void*), (p->p1, p->i1, p->p2, p->f1, p->f2, p->i2, p->i3, p->i4, p->i5, p->p3, p->p4) ); +END_API_CALLER_FUNC_void((const void*, int, const void*, float, float, int, int, int, int, const void*, const void*), (p->p1, p->i1, p->p2, p->f1, p->f2, p->i2, p->i3, p->i4, p->i5, p->p3, p->p4)); diff --git a/src/api_hook.h b/metamod/src/api_hook.h similarity index 96% rename from src/api_hook.h rename to metamod/src/api_hook.h index caf0657..6cd7402 100644 --- a/src/api_hook.h +++ b/metamod/src/api_hook.h @@ -11,10 +11,10 @@ #define _COMBINE2(x,y) x##y // simplified 'void' version of main hook function -void DLLINTERNAL main_hook_function_void(unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args); +void main_hook_function_void(unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args); // full return typed version of main hook function -void * DLLINTERNAL main_hook_function(const class_ret_t ret_init, unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args); +void *main_hook_function(const class_ret_t ret_init, unsigned int api_info_offset, enum_api_t api, unsigned int func_offset, const void * packed_args); // // API function args structures/classes @@ -286,10 +286,10 @@ PACK_ARGS_END // #ifdef __METAMOD_BUILD__ #define EXTERN_API_CALLER_FUNCTION(ret_type, args_code) \ - void * DLLINTERNAL _COMBINE4(api_caller_, ret_type, _args_, args_code)(const void * func, const void * packed_args) + void *_COMBINE4(api_caller_, ret_type, _args_, args_code)(const void * func, const void * packed_args) #else #define EXTERN_API_CALLER_FUNCTION(ret_type, args_code) \ - static const api_caller_func_t _COMBINE4(api_caller_, ret_type, _args_, args_code) DLLHIDDEN = (api_caller_func_t)0 + static const api_caller_func_t _COMBINE4(api_caller_, ret_type, _args_, args_code) = (api_caller_func_t)0 #endif EXTERN_API_CALLER_FUNCTION(void, ipV); diff --git a/src/api_info.cpp b/metamod/src/api_info.cpp similarity index 99% rename from src/api_info.cpp rename to metamod/src/api_info.cpp index ff6476d..e5f8abe 100644 --- a/src/api_info.cpp +++ b/metamod/src/api_info.cpp @@ -1,6 +1,4 @@ -#include // always -#include "api_info.h" // me -#include "api_hook.h" +#include "precompiled.h" // trace flag, loglevel, name const dllapi_info_t dllapi_info = { diff --git a/src/api_info.h b/metamod/src/api_info.h similarity index 88% rename from src/api_info.h rename to metamod/src/api_info.h index 5444d44..c3016d4 100644 --- a/src/api_info.h +++ b/metamod/src/api_info.h @@ -1,36 +1,34 @@ -#ifndef API_INFO_H -#define API_INFO_H +#pragma once #include "comp_dep.h" #include "types_meta.h" // mBOOL #include "ret_type.h" - #define P_PRE 0 // plugin function called before gamedll #define P_POST 1 // plugin function called after gamedll - // API selector -typedef enum enum_api_t { +enum enum_api_t +{ e_api_engine = 0, - e_api_dllapi = 1, - e_api_newapi = 2, -} enum_api_t; + e_api_dllapi, + e_api_newapi, +}; // API caller function prototype -typedef void * (DLLINTERNAL_NOVIS * api_caller_func_t)(const void * func, const void * packed_args); +typedef void *(DLLINTERNAL_NOVIS *api_caller_func_t)(const void *func, const void *packed_args); - -typedef struct api_info_s { +struct api_info_t +{ mBOOL trace; // if true, log info about this function int loglevel; // level at which to log info about this function api_caller_func_t api_caller; // argument format/type for single-main-hook-function optimization const char *name; // string representation of function name -} api_info_t; - +}; // DLL api functions -typedef struct dllapi_info_s { +struct dllapi_info_t +{ api_info_t pfnGameInit; api_info_t pfnSpawn; api_info_t pfnThink; @@ -81,25 +79,27 @@ typedef struct dllapi_info_s { api_info_t pfnCreateInstancedBaselines; api_info_t pfnInconsistentFile; api_info_t pfnAllowLagCompensation; - api_info_t END; -} dllapi_info_t; + // end + api_info_t END; +}; // "New" api functions -typedef struct newapi_info_s { +struct newapi_info_t +{ api_info_t pfnOnFreeEntPrivateData; api_info_t pfnGameShutdown; api_info_t pfnShouldCollide; - // Added 2005/08/11 (no SDK update): api_info_t pfnCvarValue; - // Added 2005/11/21 (no SDK update): api_info_t pfnCvarValue2; - api_info_t END; -} newapi_info_t; + // end + api_info_t END; +}; // Engine functions -typedef struct engine_info_s { +struct engine_info_t +{ api_info_t pfnPrecacheModel; api_info_t pfnPrecacheSound; api_info_t pfnSetModel; @@ -241,12 +241,9 @@ typedef struct engine_info_s { api_info_t pfnForceUnmodified; api_info_t pfnGetPlayerStats; api_info_t pfnAddServerCommand; - // Added in SDK 2.2: api_info_t pfnVoice_GetClientListening; api_info_t pfnVoice_SetClientListening; - // Added for HL 1109 (no SDK update): api_info_t pfnGetPlayerAuthId; - // Added 2003/11/10 (no SDK update): api_info_t pfnSequenceGet; api_info_t pfnSequencePickSentence; api_info_t pfnGetFileSize; @@ -258,19 +255,14 @@ typedef struct engine_info_s { api_info_t pfnProcessTutorMessageDecayBuffer; api_info_t pfnConstructTutorMessageDecayBuffer; api_info_t pfnResetTutorMessageDecayData; - // Added 2005/08/11 (no SDK update): api_info_t pfnQueryClientCvarValue; - // Added 2005/11/21 (no SDK update): api_info_t pfnQueryClientCvarValue2; - // Added 2009/06/17 (no SDK update): - api_info_t pfnCheckParm; + api_info_t pfnEngCheckParm; + // end api_info_t END; -} engine_info_t; +}; - -extern const dllapi_info_t dllapi_info DLLHIDDEN; -extern const newapi_info_t newapi_info DLLHIDDEN; -extern const engine_info_t engine_info DLLHIDDEN; - -#endif /* API_INFO_H */ +extern const dllapi_info_t dllapi_info; +extern const newapi_info_t newapi_info; +extern const engine_info_t engine_info; diff --git a/src/commands_meta.cpp b/metamod/src/commands_meta.cpp similarity index 61% rename from src/commands_meta.cpp rename to metamod/src/commands_meta.cpp index 22e9e82..b8b8afb 100644 --- a/src/commands_meta.cpp +++ b/metamod/src/commands_meta.cpp @@ -1,39 +1,33 @@ -#include // strtol() -#include // always -#include "commands_meta.h" // me -#include "metamod.h" // Plugins, etc -#include "log_meta.h" // META_CONS, etc -#include "info_name.h" // VNAME, etc -#include "vdate.h" // COMPILE_TIME, COMPILE_TZONE +#include "precompiled.h" #ifdef META_PERFMON -long double total_tsc=0; -unsigned long long count_tsc=0; -unsigned long long active_tsc=0; -unsigned long long min_tsc=0; +long double total_tsc = 0; +unsigned long long count_tsc = 0; +unsigned long long active_tsc = 0; +unsigned long long min_tsc = 0; -void DLLINTERNAL cmd_meta_tsc(void) +void cmd_meta_tsc() { - if(!count_tsc) + if (!count_tsc) return; - + META_CONS(" "); META_CONS(" count_tsc: %.0f", (double)count_tsc); META_CONS(" mean_tsc: %.1f", (double)(total_tsc / count_tsc)); META_CONS(" min_tsc: %.0f", (double)min_tsc); } -void DLLINTERNAL cmd_meta_reset_tsc(void) +void cmd_meta_reset_tsc() { - total_tsc=0; - count_tsc=0; - min_tsc=0; + total_tsc = 0; + count_tsc = 0; + min_tsc = 0; } -#endif /*META_PERFMON*/ +#endif // Register commands and cvars. -void DLLINTERNAL meta_register_cmdcvar() +void meta_register_cmdcvar() { CVAR_REGISTER(&meta_debug); CVAR_REGISTER(&meta_version); @@ -42,76 +36,61 @@ void DLLINTERNAL meta_register_cmdcvar() } // Parse "meta" console command. -void DLLHIDDEN svr_meta(void) +void svr_meta() { - const char *cmd; - cmd=CMD_ARGV(1); - // arguments: none - if(!strcasecmp(cmd, "version")) - cmd_meta_version(); - else if(!strcasecmp(cmd, "gpl")) - cmd_meta_gpl(); - else if(!strcasecmp(cmd, "refresh")) - cmd_meta_refresh(); - else if(!strcasecmp(cmd, "list")) - cmd_meta_pluginlist(); - else if(!strcasecmp(cmd, "cmds")) - cmd_meta_cmdlist(); - else if(!strcasecmp(cmd, "cvars")) - cmd_meta_cvarlist(); - else if(!strcasecmp(cmd, "game")) - cmd_meta_game(); - else if(!strcasecmp(cmd, "config")) - cmd_meta_config(); - // arguments: existing plugin(s) - else if(!strcasecmp(cmd, "pause")) - cmd_doplug(PC_PAUSE); - else if(!strcasecmp(cmd, "unpause")) - cmd_doplug(PC_UNPAUSE); - else if(!strcasecmp(cmd, "unload")) - cmd_doplug(PC_UNLOAD); - else if(!strcasecmp(cmd, "force_unload")) - cmd_doplug(PC_FORCE_UNLOAD); - else if(!strcasecmp(cmd, "reload")) - cmd_doplug(PC_RELOAD); - else if(!strcasecmp(cmd, "retry")) - cmd_doplug(PC_RETRY); - else if(!strcasecmp(cmd, "clear")) - cmd_doplug(PC_CLEAR); - else if(!strcasecmp(cmd, "info")) - cmd_doplug(PC_INFO); - else if(!strcasecmp(cmd, "require")) - cmd_doplug(PC_REQUIRE); - // arguments: filename, description - else if(!strcasecmp(cmd, "load")) - cmd_meta_load(); -#ifdef META_PERFMON - else if(!strcasecmp(cmd, "tsc")) - cmd_meta_tsc(); - else if(!strcasecmp(cmd, "reset_tsc")) - cmd_meta_reset_tsc(); -#endif /*META_PERFMON*/ - // unrecognized - else { - META_CONS("Unrecognized meta command: %s", cmd); - cmd_meta_usage(); - return; + const char *cmd = CMD_ARGV(1); + +#define PARSE_KEY(key, func, ...)\ + if (!Q_stricmp(cmd, key)) {\ + func(__VA_ARGS__);\ + return;\ } + + PARSE_KEY("version", cmd_meta_version); + PARSE_KEY("gpl", cmd_meta_gpl); + PARSE_KEY("refresh", cmd_meta_refresh); + PARSE_KEY("list", cmd_meta_pluginlist); + PARSE_KEY("cmds", cmd_meta_cmdlist); + PARSE_KEY("cvars", cmd_meta_cvarlist); + PARSE_KEY("game", cmd_meta_game); + PARSE_KEY("config", cmd_meta_config); + + PARSE_KEY("pause", cmd_doplug, PC_PAUSE); + PARSE_KEY("unpause", cmd_doplug, PC_UNPAUSE); + PARSE_KEY("unload", cmd_doplug, PC_UNPAUSE); + PARSE_KEY("force_unload", cmd_doplug, PC_FORCE_UNLOAD); + PARSE_KEY("reload", cmd_doplug, PC_RELOAD); + PARSE_KEY("retry", cmd_doplug, PC_RETRY); + PARSE_KEY("clear", cmd_doplug, PC_CLEAR); + PARSE_KEY("info", cmd_doplug, PC_INFO); + PARSE_KEY("require", cmd_doplug, PC_REQUIRE); + + PARSE_KEY("load", cmd_meta_load) + +#ifdef META_PERFMON + PARSE_KEY("tsc", cmd_meta_tsc); + PARSE_KEY("reset_tsc", cmd_meta_reset_tsc); +#endif + + // unrecognized + META_CONS("Unrecognized meta command: %s", cmd); + cmd_meta_usage(); } // Parse "meta" client command. -void DLLINTERNAL client_meta(edict_t *pEntity) +void client_meta(edict_t *pEntity) { - const char *cmd; - cmd=CMD_ARGV(1); - META_LOG("ClientCommand 'meta %s' from player '%s'", - CMD_ARGS(), STRING(pEntity->v.netname)); + const char *cmd = CMD_ARGV(1); + META_LOG("ClientCommand 'meta %s' from player '%s'", CMD_ARGS(), STRING(pEntity->v.netname)); + // arguments: none - if(strmatch(cmd, "version")) + if (!Q_strcmp(cmd, "version")) client_meta_version(pEntity); - else if(strmatch(cmd, "list")) + + else if (!Q_strcmp(cmd, "list")) client_meta_pluginlist(pEntity); - else { + else + { META_CLIENT(pEntity, "Unrecognized meta command: %s", cmd); client_meta_usage(pEntity); return; @@ -119,7 +98,7 @@ void DLLINTERNAL client_meta(edict_t *pEntity) } // Print usage for "meta" console command. -void DLLINTERNAL cmd_meta_usage(void) { +void cmd_meta_usage() { META_CONS("usage: meta []"); META_CONS("valid commands are:"); META_CONS(" version - display metamod version info"); @@ -142,7 +121,7 @@ void DLLINTERNAL cmd_meta_usage(void) { } // Print usage for "meta" client command. -void DLLINTERNAL client_meta_usage(edict_t *pEntity) +void client_meta_usage(edict_t *pEntity) { META_CLIENT(pEntity, "usage: meta []"); META_CLIENT(pEntity, "valid commands are:"); @@ -151,54 +130,46 @@ void DLLINTERNAL client_meta_usage(edict_t *pEntity) } // "meta version" console command. -void DLLINTERNAL cmd_meta_version(void) +void cmd_meta_version() { if (CMD_ARGC() != 2) { META_CONS("usage: meta version"); return; } - META_CONS("%s v%s %s (%s)", VNAME, VVERSION, VDATE, META_INTERFACE_VERSION); - META_CONS("by %s", VAUTHOR); - META_CONS(" %s", VURL); - META_CONS(" Patch: %s v%d", VPATCH_NAME, VPATCH_IVERSION); - META_CONS(" by %s", VPATCH_AUTHOR); - META_CONS(" %s", VPATCH_WEBSITE); - META_CONS(" Modification: v%s from ReHLDS Team (C) 2016", VPATCH_MODIFICATION); - META_CONS("compiled: %s %s (%s)", COMPILE_TIME, COMPILE_TZONE, OPT_TYPE); + + META_CONS("Metamod v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION); + META_CONS("Metamod build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")"); + META_CONS("Metamod from: " APP_COMMITS_URL APP_COMMIT_ID " " APP_COMMIT_AUTHOR ""); } // "meta version" client command. -void DLLINTERNAL client_meta_version(edict_t *pEntity) +void client_meta_version(edict_t *pEntity) { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CLIENT(pEntity, "usage: meta version"); return; } - META_CLIENT(pEntity, "%s v%s %s (%s)", VNAME, VVERSION, VDATE, META_INTERFACE_VERSION); - META_CLIENT(pEntity, "by %s", VAUTHOR); - META_CLIENT(pEntity, " %s", VURL); - META_CLIENT(pEntity, " Patch: %s v%d", VPATCH_NAME, VPATCH_IVERSION); - META_CLIENT(pEntity, " by %s", VPATCH_AUTHOR); - META_CLIENT(pEntity, " %s", VPATCH_WEBSITE); - META_CLIENT(pEntity, "compiled: %s %s (%s)", COMPILE_TIME, COMPILE_TZONE, OPT_TYPE); - META_CLIENT(pEntity, "ifvers: %s", META_INTERFACE_VERSION); + + META_CONS("Metamod v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION); + META_CONS("Metamod build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")"); + META_CONS("Metamod from: " APP_COMMITS_URL APP_COMMIT_ID " " APP_COMMIT_AUTHOR ""); } // "meta gpl" console command. -void DLLINTERNAL cmd_meta_gpl(void) +void cmd_meta_gpl() { - META_CONS("%s version %s %s", VNAME, VVERSION, VDATE); - META_CONS("Copyright (c) 2001-%s %s", COPYRIGHT_YEAR, VAUTHOR); + META_CONS("Metamod version " __TIME__ " " __DATE__); + META_CONS("Copyright (c) 2001-2016 Will Day (modification ReHLDS Team)"); META_CONS(""); - META_CONS(" %s is free software; you can redistribute it and/or", VNAME); + META_CONS(" Metamod is free software; you can redistribute it and/or"); META_CONS(" modify it under the terms of the GNU General Public License"); META_CONS(" as published by the Free Software Foundation; either"); META_CONS(" version 2 of the License, or (at your option) any later"); META_CONS(" version."); META_CONS(" "); - META_CONS(" %s is distributed in the hope that it will be useful,", VNAME); + META_CONS(" Metamod is distributed in the hope that it will be useful,"); META_CONS(" but WITHOUT ANY WARRANTY; without even the implied warranty"); META_CONS(" of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); META_CONS(" See the GNU General Public License for more details."); @@ -221,13 +192,14 @@ void DLLINTERNAL cmd_meta_gpl(void) } // "meta game" console command. -void DLLINTERNAL cmd_meta_game(void) +void cmd_meta_game() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta game"); return; } + META_CONS("GameDLL info:"); META_CONS(" name: %s", GameDLL.name); META_CONS(" desc: %s", GameDLL.desc); @@ -238,72 +210,78 @@ void DLLINTERNAL cmd_meta_game(void) } // "meta refresh" console command. -void DLLINTERNAL cmd_meta_refresh(void) +void cmd_meta_refresh() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta refresh"); return; } + META_LOG("Refreshing the plugins on demand..."); - if(Plugins->refresh(PT_ANYTIME) != mTRUE) + if (Plugins->refresh(PT_ANYTIME) != mTRUE) { META_LOG("Refresh failed."); } } // "meta list" console command. -void DLLINTERNAL cmd_meta_pluginlist(void) +void cmd_meta_pluginlist() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta list"); return; } + Plugins->show(); } // "meta list" client command. -void DLLINTERNAL client_meta_pluginlist(edict_t *pEntity) +void client_meta_pluginlist(edict_t *pEntity) { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CLIENT(pEntity, "usage: meta list"); return; } + Plugins->show_client(pEntity); } // "meta cmds" console command. -void DLLINTERNAL cmd_meta_cmdlist(void) +void cmd_meta_cmdlist() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta cmds"); return; } + RegCmds->show(); } // "meta cvars" console command. -void DLLINTERNAL cmd_meta_cvarlist(void) +void cmd_meta_cvarlist() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta cvars"); return; } + RegCvars->show(); } // "meta config" console command. -void DLLINTERNAL cmd_meta_config(void) +void cmd_meta_config() { - if(CMD_ARGC() != 2) + if (CMD_ARGC() != 2) { META_CONS("usage: meta cvars"); return; } + Config->show(); } @@ -320,68 +298,61 @@ void DLLINTERNAL cmd_meta_config(void) // path_i386.so, path_i486.so, etc // "meta load" console command. -void DLLINTERNAL cmd_meta_load(void) +void cmd_meta_load() { - int argc; - const char *args; - argc=CMD_ARGC(); - if(argc < 3) { + int argc = CMD_ARGC(); + if (argc < 3) { META_CONS("usage: meta load []"); META_CONS(" where is an identifier used to locate the plugin file."); META_CONS(" The system will look for a number of files based on this name, including:"); META_CONS(" name"); -#ifdef linux +#ifdef _WIN32 + META_CONS(" name.dll"); + META_CONS(" name_mm.dll"); + META_CONS(" mm_name.dll"); +#else META_CONS(" name.so"); META_CONS(" name_mm.so"); META_CONS(" name_MM.so"); META_CONS(" mm_name.so"); -#ifdef __x86_64__ - META_CONS(" name_amd64.so"); - META_CONS(" name_x86_64.so"); -#else - META_CONS(" name_i386.so"); - META_CONS(" name_i686.so"); #endif -#elif defined(_WIN32) - META_CONS(" name.dll"); - META_CONS(" name_mm.dll"); - META_CONS(" mm_name.dll"); -#endif /* linux */ + META_CONS(" in a number of directories, including:"); META_CONS(" "); META_CONS(" /dlls"); META_CONS(" "); return; } - args=CMD_ARGS(); + const char *args = CMD_ARGS(); // cmd_addload() handles all the feedback to the console.. Plugins->cmd_addload(args); } // Handle various console commands that refer to a known/loaded plugin. -void DLLINTERNAL cmd_doplug(PLUG_CMD pcmd) +void cmd_doplug(PLUG_CMD pcmd) { - int i=0, argc; - const char *cmd, *arg; MPlugin *findp; - argc=CMD_ARGC(); - cmd=CMD_ARGV(1); - if(argc < 3) + int argc = CMD_ARGC(); + const char *cmd = CMD_ARGV(1); + + if (argc < 3) { META_CONS("usage: meta %s [ ...]", cmd); META_CONS(" where can be either the plugin index #"); META_CONS(" or a non-ambiguous prefix string matching name, desc, file, or logtag"); return; } + // i=2 to skip first arg, as that's the "cmd" - for(i=2; i < argc; i++) + for (int i = 2; i < argc; i++) { - int pindex; - char *endptr; - arg=CMD_ARGV(i); + const char *arg = CMD_ARGV(i); + // try to match plugin id first - pindex = strtol(arg, &endptr, 10); - if(*arg && !*endptr) + char *endptr; + int pindex = strtol(arg, &endptr, 10); + + if (*arg && !*endptr) findp=Plugins->find(pindex); // else try to match some string (prefix) else @@ -391,25 +362,28 @@ void DLLINTERNAL cmd_doplug(PLUG_CMD pcmd) // - specified plugin was found in the list of current plugins // - plugin successfully loaded and began running // Otherwise, print error and exit. - if(pcmd==PC_REQUIRE) { - if(findp && findp->status >= PL_RUNNING) { + if (pcmd == PC_REQUIRE) + { + if (findp && findp->status >= PL_RUNNING) + { META_DEBUG(3, ("Required plugin '%s' found loaded and running.", arg)); return; } // Output to both places, because we don't want the admin // to miss this.. - if(!findp && meta_errno == ME_NOTUNIQ) { + if (!findp && meta_errno == ME_NOTUNIQ) + { META_ERROR("Unique match for required plugin '%s' was not found! Exiting.", arg); META_CONS("\nERROR: Unique match for required plugin '%s' was not found! Exiting.\n", arg); } - else if(!findp) { - META_ERROR("Required plugin '%s' was not found! Exiting.", - arg); - META_CONS("\nERROR: Required plugin '%s' was not found! Exiting.\n", - arg); + else if (!findp) + { + META_ERROR("Required plugin '%s' was not found! Exiting.", arg); + META_CONS("\nERROR: Required plugin '%s' was not found! Exiting.\n", arg); } - else { + else + { META_ERROR("Required plugin '%s' did not load successfully! (status=%s) Exiting.", arg, findp->str_status(ST_SIMPLE)); META_CONS("\nERROR: Required plugin '%s' did not load successfully! (status=%s) Exiting.\n", arg, findp->str_status(ST_SIMPLE)); } @@ -417,74 +391,86 @@ void DLLINTERNAL cmd_doplug(PLUG_CMD pcmd) do_exit(1); } - if(!findp) { - if(meta_errno == ME_NOTUNIQ) + if (!findp) + { + if (meta_errno == ME_NOTUNIQ) META_CONS("Couldn't find unique plugin matching '%s'", arg); else META_CONS("Couldn't find plugin matching '%s'", arg); return; } - if(pcmd==PC_PAUSE) { - if(findp->pause()) + if (pcmd == PC_PAUSE) + { + if (findp->pause()) META_CONS("Paused plugin '%s'", findp->desc); else META_CONS("Pause failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_UNPAUSE) { - if(findp->unpause()) + else if (pcmd == PC_UNPAUSE) + { + if (findp->unpause()) META_CONS("Unpaused plugin '%s'", findp->desc); else META_CONS("Unpause failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_UNLOAD) { - findp->action=PA_UNLOAD; - if(findp->unload(PT_ANYTIME, PNL_COMMAND, PNL_COMMAND)) { + else if (pcmd == PC_UNLOAD) + { + findp->action = PA_UNLOAD; + if (findp->unload(PT_ANYTIME, PNL_COMMAND, PNL_COMMAND)) + { META_CONS("Unloaded plugin '%s'", findp->desc); Plugins->show(); } - else if(meta_errno == ME_DELAYED) + else if (meta_errno == ME_DELAYED) META_CONS("Unload delayed for plugin '%s'", findp->desc); else META_CONS("Unload failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_FORCE_UNLOAD) { - findp->action=PA_UNLOAD; - if(findp->unload(PT_ANYTIME, PNL_CMD_FORCED, PNL_CMD_FORCED)) { + else if (pcmd == PC_FORCE_UNLOAD) + { + findp->action = PA_UNLOAD; + if (findp->unload(PT_ANYTIME, PNL_CMD_FORCED, PNL_CMD_FORCED)) + { META_CONS("Forced unload plugin '%s'", findp->desc); Plugins->show(); } else META_CONS("Forced unload failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_RELOAD) { - findp->action=PA_RELOAD; - if(findp->reload(PT_ANYTIME, PNL_COMMAND)) + else if (pcmd == PC_RELOAD) + { + findp->action = PA_RELOAD; + if (findp->reload(PT_ANYTIME, PNL_COMMAND)) META_CONS("Reloaded plugin '%s'", findp->desc); - else if(meta_errno == ME_DELAYED) + else if (meta_errno == ME_DELAYED) META_CONS("Reload delayed for plugin '%s'", findp->desc); - else if(meta_errno == ME_NOTALLOWED) + else if (meta_errno == ME_NOTALLOWED) META_CONS("Reload not allowed for plugin '%s' now, only allowed %s", findp->desc, findp->str_loadable(SL_ALLOWED)); else META_CONS("Reload failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_RETRY) { - if(findp->retry(PT_ANYTIME, PNL_COMMAND)) + else if (pcmd == PC_RETRY) + { + if (findp->retry(PT_ANYTIME, PNL_COMMAND)) META_CONS("Retry succeeded for plugin '%s'", findp->desc); else META_CONS("Retry failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_CLEAR) { - if(findp->clear()) { + else if (pcmd == PC_CLEAR) + { + if (findp->clear()) + { META_CONS("Cleared failed plugin '%s' from list", findp->desc); Plugins->show(); } else META_CONS("Clear failed for plugin '%s'", findp->desc); } - else if(pcmd==PC_INFO) + else if (pcmd == PC_INFO) findp->show(); - else { + else + { META_WARNING("Unexpected plug_cmd: %d", pcmd); META_CONS("Command failed; see log"); } diff --git a/metamod/src/commands_meta.h b/metamod/src/commands_meta.h new file mode 100644 index 0000000..a20a128 --- /dev/null +++ b/metamod/src/commands_meta.h @@ -0,0 +1,44 @@ +#pragma once + +#include "types_meta.h" // mBOOL +#include "comp_dep.h" + +// Flags to use for meta_cmd_doplug(), to operate on existing plugins; note +// "load" operates on a non-existing plugin thus isn't included here. +typedef enum { + PC_NULL = 0, + PC_PAUSE, // pause the plugin + PC_UNPAUSE, // unpause the plugin + PC_UNLOAD, // unload the plugin + PC_RELOAD, // unload the plugin and load it again + PC_RETRY, // retry a failed operation (usually load/attach) + PC_INFO, // show all info about the plugin + PC_CLEAR, // remove a failed plugin from the list + PC_FORCE_UNLOAD, // forcibly unload the plugin + PC_REQUIRE, // require that this plugin is loaded/running +} PLUG_CMD; + +void meta_register_cmdcvar(); + +void svr_meta(); // only hidden because called from outside! + +void cmd_meta_usage(); +void cmd_meta_version(); +void cmd_meta_gpl(); + +void cmd_meta_game(); +void cmd_meta_refresh(); +void cmd_meta_load(); + +void cmd_meta_pluginlist(); +void cmd_meta_cmdlist(); +void cmd_meta_cvarlist(); +void cmd_meta_config(); + +void cmd_doplug(PLUG_CMD pcmd); + +void client_meta(edict_t *pEntity); +void client_meta_usage(edict_t *pEntity); +void client_meta_version(edict_t *pEntity); +void client_meta_pluginlist(edict_t *pEntity); +void client_meta_aybabtu(edict_t *pEntity); diff --git a/src/comp_dep.h b/metamod/src/comp_dep.h similarity index 94% rename from src/comp_dep.h rename to metamod/src/comp_dep.h index c6817e5..ccd733a 100644 --- a/src/comp_dep.h +++ b/metamod/src/comp_dep.h @@ -12,8 +12,6 @@ // We use these macros to hide our internal globals from being exported // on ELF .so #if defined(__GNUC__) && !defined(_WIN32) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 3 - // Hidden data/function. - #define DLLHIDDEN __attribute__((visibility("hidden"))) // Hidden internal function. #if defined(__x86_64__) || defined(__amd64__) #define DLLINTERNAL __attribute__((visibility("internal"))) @@ -28,7 +26,6 @@ #endif #endif #else - #define DLLHIDDEN #if defined (_WIN32) && defined (_MSC_VER) #define DLLINTERNAL_NOVIS #define DLLINTERNAL diff --git a/metamod/src/conf_meta.cpp b/metamod/src/conf_meta.cpp new file mode 100644 index 0000000..c577d42 --- /dev/null +++ b/metamod/src/conf_meta.cpp @@ -0,0 +1,192 @@ +#include "precompiled.h" + +MConfig::MConfig() + : list(nullptr), filename(nullptr), debuglevel(0), plugins_file(nullptr), exec_cfg(nullptr) +{ +} + +// Initialize default values from the stored options struct. Has to happen +// _after_ constructor, so that all the fields are allocated (d'oh). +void MConfig::init(option_t *global_options) +{ + option_t *optp; + list=global_options; + for (optp=list; optp->name; optp++) + set(optp, optp->init); +} + +option_t *MConfig::find(const char *lookup) +{ + option_t *optp; + + for (optp = list; optp->name && Q_strcmp(optp->name, lookup); optp++); + + if (optp->name) + return optp; + else + RETURN_ERRNO(nullptr, ME_NOTFOUND); +} + +mBOOL MConfig::set(const char *key, const char *value) +{ + option_t *optp; + optp=find(key); + if (optp) + return set(optp, value); + else + RETURN_ERRNO(mFALSE, ME_NOTFOUND); +} + +mBOOL MConfig::set(option_t *setp, const char *setstr) +{ + char pathbuf[PATH_MAX]; + int *optval = (int *) setp->dest; + char **optstr = (char **) setp->dest; + + if (!setstr) + return mTRUE; + + switch (setp->type) + { + case CF_INT: + if (!isdigit(setstr[0])) + { + META_WARNING("option '%s' invalid format '%s'", setp->name, setstr); + RETURN_ERRNO(mFALSE, ME_FORMAT); + } + + *optval = Q_atoi(setstr); + META_DEBUG(3, ("set config int: %s = %d", setp->name, *optval)); + break; + case CF_BOOL: + if (!Q_stricmp(setstr, "true") || !Q_stricmp(setstr, "yes") || !Q_strcmp(setstr, "1")) + { + *optval = 1; + } + else if (!Q_stricmp(setstr, "false") || !Q_stricmp(setstr, "no") || !Q_strcmp(setstr, "0")) + { + *optval = 0; + } + else + { + META_WARNING("option '%s' invalid format '%s'", setp->name, setstr); + RETURN_ERRNO(mFALSE, ME_FORMAT); + } + META_DEBUG(3, ("set config bool: %s = %s", setp->name, *optval ? "true" : "false")); + break; + case CF_STR: + if (*optstr) + free(*optstr); + *optstr = Q_strdup(setstr); + META_DEBUG(3, ("set config string: %s = %s", setp->name, *optstr)); + break; + case CF_PATH: + if (*optstr) + free(*optstr); + + full_gamedir_path(setstr, pathbuf); + *optstr = Q_strdup(pathbuf); + META_DEBUG(3, ("set config path: %s = %s", setp->name, *optstr)); + break; + + default: + META_WARNING("unrecognized config type '%d'", setp->type); + RETURN_ERRNO(mFALSE, ME_ARGUMENT); + } + + return mTRUE; +} + +mBOOL MConfig::load(const char *fn) +{ + FILE *fp; + char loadfile[PATH_MAX]; + char line[MAX_CONF_LEN]; + char *optname, *optval; + option_t *optp; + int ln; + + // Make full pathname (from gamedir if relative, collapse "..", + // backslashes, etc). + full_gamedir_path(fn, loadfile); + + fp = fopen(loadfile, "r"); + if (!fp) + { + META_WARNING("unable to open config file '%s': %s", loadfile, strerror(errno)); + RETURN_ERRNO(mFALSE, ME_NOFILE); + } + + META_DEBUG(2, ("Loading from config file: %s", loadfile)); + for (ln = 1; !feof(fp) && fgets(line, sizeof(line), fp); ln++) + { + if (line[0] == '#' || line[0] == ';') + continue; + + if (!Q_strncmp(line, "//", 2)) + continue; + + if (!(optname = strtok(line, " \t\r\n"))) + { + META_WARNING("'%s' line %d: bad config format: missing option", loadfile, ln); + continue; + } + + if (!(optval = strtok(NULL, "\r\n"))) + { + META_WARNING("'%s' line %d: bad config format: missing value", loadfile, ln); + continue; + } + + if (!(optp = find(optname))) + { + META_WARNING("'%s' line %d: unknown option name '%s'", loadfile, ln, optname); + continue; + } + + if (!set(optp, optval)) + { + META_WARNING("'%s' line %d: unable to set option '%s' value '%s'", loadfile, ln, optname, optval); + continue; + } + } + + filename = strdup(loadfile); + fclose(fp); + + return mTRUE; +} + +void MConfig::show() +{ + option_t *optp; + + if (filename) + META_CONS("%s and %s:", "Config options from localinfo", filename); + else + META_CONS("%s:", "Config options from localinfo"); + + for (optp = list; optp->name; optp++) + { + int *optval = (int *)optp->dest; + char **optstr = (char **)optp->dest; + // cvar_t *optcvar = (cvar_t *) optp->dest; + // SETOPT_FN optcmd = (SETOPT_FN) optp->dest; + + switch (optp->type) + { + case CF_INT: + META_CONS(" %-20s\t%d\n", optp->name, *optval); + break; + case CF_BOOL: + META_CONS(" %-20s\t%s\n", optp->name, *optval ? "true" : "false"); + break; + case CF_STR: + case CF_PATH: + META_CONS(" %-20s\t%s\n", optp->name, *optstr ? *optstr : ""); + break; + case CF_NONE: + break; + } + } +} diff --git a/metamod/src/conf_meta.h b/metamod/src/conf_meta.h new file mode 100644 index 0000000..2dd5a9e --- /dev/null +++ b/metamod/src/conf_meta.h @@ -0,0 +1,54 @@ +#pragma once + +#include "types_meta.h" // mBOOL +#include "new_baseclass.h" +#include "comp_dep.h" + +// Max length of line in config file. +#define MAX_CONF_LEN 1024 + +// Supported config value-types. +enum cf_type_t +{ + CF_NONE = 0, + CF_INT, + CF_BOOL, + CF_STR, + CF_PATH, +}; + +struct option_t +{ + char *name; // option name + cf_type_t type; // option type + void *dest; // addr of destination variable, or handler function + char *init; // initial value, as a string, just as config file would +}; + +class MConfig: public class_metamod_new { +public: + // contructor + MConfig(); + // data + int debuglevel; // to use for meta_debug + char *plugins_file; // ie metamod.ini, plugins.ini + char *exec_cfg; // ie metaexec.cfg, exec.cfg + int clientmeta; // control 'meta' client-command + // functions + void init(option_t *global_options); + mBOOL load(const char *filename); + mBOOL set(const char *key, const char *value); + void show(); + +private: + // data + option_t *list; + char *filename; + // functions + option_t *find(const char *lookup); + mBOOL set(option_t *setp, const char *value); + // Private; to satisfy -Weffc++ "has pointer data members but does + // not override" copy/assignment constructor. + void operator=(const MConfig &src); + MConfig(const MConfig &src); +}; diff --git a/src/dllapi.cpp b/metamod/src/dllapi.cpp similarity index 91% rename from src/dllapi.cpp rename to metamod/src/dllapi.cpp index 7e7f28f..c9bff78 100644 --- a/src/dllapi.cpp +++ b/metamod/src/dllapi.cpp @@ -1,11 +1,4 @@ -#include // offsetof -#include // always -#include "dllapi.h" // me -#include "metamod.h" // SETUP_API_CALLS, etc -#include "api_info.h" // dllapi_info, etc -#include "commands_meta.h" // client_meta, etc -#include "log_meta.h" // META_ERROR, etc -#include "api_hook.h" +#include "precompiled.h" // Original DLL routines, functions returning "void". #define META_DLLAPI_HANDLE_void(FN_TYPE, pfnName, pack_args_type, pfn_args) \ @@ -37,7 +30,7 @@ // From SDK dlls/game.cpp: -static void mm_GameDLLInit(void) { +static void mm_GameDLLInit() { META_DLLAPI_HANDLE_void(FN_GAMEINIT, pfnGameInit, void, (VOID_ARG)); RETURN_API_void(); } @@ -99,7 +92,7 @@ static void mm_RestoreGlobalState(SAVERESTOREDATA *pSaveData) { META_DLLAPI_HANDLE_void(FN_RESTOREGLOBALSTATE, pfnRestoreGlobalState, p, (pSaveData)); RETURN_API_void(); } -static void mm_ResetGlobalState(void) { +static void mm_ResetGlobalState() { META_DLLAPI_HANDLE_void(FN_RESETGLOBALSTATE, pfnResetGlobalState, void, (VOID_ARG)); RETURN_API_void(); } @@ -124,7 +117,7 @@ static void mm_ClientPutInServer(edict_t *pEntity) { RETURN_API_void(); } static void mm_ClientCommand(edict_t *pEntity) { - if(Config->clientmeta && strmatch(CMD_ARGV(0), "meta")) { + if (Config->clientmeta && !Q_strcmp(CMD_ARGV(0), "meta")) { client_meta(pEntity); } META_DLLAPI_HANDLE_void(FN_CLIENTCOMMAND, pfnClientCommand, p, (pEntity)); @@ -138,10 +131,10 @@ static void mm_ServerActivate(edict_t *pEdictList, int edictCount, int clientMax META_DLLAPI_HANDLE_void(FN_SERVERACTIVATE, pfnServerActivate, p2i, (pEdictList, edictCount, clientMax)); RETURN_API_void(); } -static void mm_ServerDeactivate(void) { +static void mm_ServerDeactivate() { META_DLLAPI_HANDLE_void(FN_SERVERDEACTIVATE, pfnServerDeactivate, void, (VOID_ARG)); // Update loaded plugins. Look for new plugins in inifile, as well as - // any plugins waiting for a changelevel to load. + // any plugins waiting for a changelevel to load. // // This is done in ServerDeactivate rather than Activate, as the latter // isn't actually the first routine to be called on a new map. In @@ -168,21 +161,21 @@ static void mm_PlayerPostThink(edict_t *pEntity) { META_DLLAPI_HANDLE_void(FN_PLAYERPOSTTHINK, pfnPlayerPostThink, p, (pEntity)); RETURN_API_void(); } -static void mm_StartFrame(void) { +static void mm_StartFrame() { meta_debug_value = (int)meta_debug.value; META_DLLAPI_HANDLE_void(FN_STARTFRAME, pfnStartFrame, void, (VOID_ARG)); RETURN_API_void(); } -static void mm_ParmsNewLevel(void) { +static void mm_ParmsNewLevel() { META_DLLAPI_HANDLE_void(FN_PARMSNEWLEVEL, pfnParmsNewLevel, void, (VOID_ARG)); RETURN_API_void(); } -static void mm_ParmsChangeLevel(void) { +static void mm_ParmsChangeLevel() { META_DLLAPI_HANDLE_void(FN_PARMSCHANGELEVEL, pfnParmsChangeLevel, void, (VOID_ARG)); RETURN_API_void(); } -static const char *mm_GetGameDescription(void) { +static const char *mm_GetGameDescription() { META_DLLAPI_HANDLE(const char *, NULL, FN_GETGAMEDESCRIPTION, pfnGetGameDescription, void, (VOID_ARG)); RETURN_API(const char *); } @@ -208,7 +201,7 @@ static void mm_Sys_Error(const char *error_string) { } // From SDK pm_shared/pm_shared.c: -static void mm_PM_Move (struct playermove_s *ppmove, int server) { +static void mm_PM_Move(struct playermove_s *ppmove, int server) { META_DLLAPI_HANDLE_void(FN_PM_MOVE, pfnPM_Move, pi, (ppmove, server)); RETURN_API_void(); } @@ -216,7 +209,7 @@ static void mm_PM_Init(struct playermove_s *ppmove) { META_DLLAPI_HANDLE_void(FN_PM_INIT, pfnPM_Init, p, (ppmove)); RETURN_API_void(); } -static char mm_PM_FindTextureType(const char *name) { +static char mm_PM_FindTextureType(char *name) { META_DLLAPI_HANDLE(const char, '\0', FN_PM_FINDTEXTURETYPE, pfnPM_FindTextureType, p, (name)); RETURN_API(const char); } @@ -226,7 +219,7 @@ static void mm_SetupVisibility(edict_t *pViewEntity, edict_t *pClient, unsigned META_DLLAPI_HANDLE_void(FN_SETUPVISIBILITY, pfnSetupVisibility, 4p, (pViewEntity, pClient, pvs, pas)); RETURN_API_void(); } -static void mm_UpdateClientData (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) { +static void mm_UpdateClientData(const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) { META_DLLAPI_HANDLE_void(FN_UPDATECLIENTDATA, pfnUpdateClientData, pip, (ent, sendweapons, cd)); RETURN_API_void(); } @@ -238,7 +231,7 @@ static void mm_CreateBaseline(int player, int eindex, struct entity_state_s *bas META_DLLAPI_HANDLE_void(FN_CREATEBASELINE, pfnCreateBaseline, 2i2pi2p, (player, eindex, baseline, entity, playermodelindex, (float*)player_mins, (float*)player_maxs)); RETURN_API_void(); } -static void mm_RegisterEncoders(void) { +static void mm_RegisterEncoders() { META_DLLAPI_HANDLE_void(FN_REGISTERENCODERS, pfnRegisterEncoders, void, (VOID_ARG)); RETURN_API_void(); } @@ -250,7 +243,7 @@ static void mm_CmdStart(const edict_t *player, const struct usercmd_s *cmd, unsi META_DLLAPI_HANDLE_void(FN_CMDSTART, pfnCmdStart, 2pui, (player, cmd, random_seed)); RETURN_API_void(); } -static void mm_CmdEnd (const edict_t *player) { +static void mm_CmdEnd(const edict_t *player) { META_DLLAPI_HANDLE_void(FN_CMDEND, pfnCmdEnd, p, (player)); RETURN_API_void(); } @@ -262,7 +255,7 @@ static int mm_GetHullBounds(int hullnumber, float *mins, float *maxs) { META_DLLAPI_HANDLE(int, 0, FN_GETHULLBOUNDS, pfnGetHullBounds, i2p, (hullnumber, mins, maxs)); RETURN_API(int); } -static void mm_CreateInstancedBaselines (void) { +static void mm_CreateInstancedBaselines() { META_DLLAPI_HANDLE_void(FN_CREATEINSTANCEDBASELINES, pfnCreateInstancedBaselines, void, (VOID_ARG)); RETURN_API_void(); } @@ -270,7 +263,7 @@ static int mm_InconsistentFile(const edict_t *player, const char *filename, char META_DLLAPI_HANDLE(int, 0, FN_INCONSISTENTFILE, pfnInconsistentFile, 3p, (player, filename, disconnect_message)); RETURN_API(int); } -static int mm_AllowLagCompensation(void) { +static int mm_AllowLagCompensation() { META_DLLAPI_HANDLE(int, 0, FN_ALLOWLAGCOMPENSATION, pfnAllowLagCompensation, void, (VOID_ARG)); RETURN_API(int); } @@ -282,7 +275,7 @@ static void mm_OnFreeEntPrivateData(edict_t *pEnt) { META_NEWAPI_HANDLE_void(FN_ONFREEENTPRIVATEDATA, pfnOnFreeEntPrivateData, p, (pEnt)); RETURN_API_void(); } -static void mm_GameShutdown(void) { +static void mm_GameShutdown() { META_NEWAPI_HANDLE_void(FN_GAMESHUTDOWN, pfnGameShutdown, void, (VOID_ARG)); RETURN_API_void(); } @@ -294,19 +287,19 @@ static int mm_ShouldCollide(edict_t *pentTouched, edict_t *pentOther) { static void mm_CvarValue(const edict_t *pEnt, const char *value) { g_Players.clear_player_cvar_query(pEnt); META_NEWAPI_HANDLE_void(FN_CVARVALUE, pfnCvarValue, 2p, (pEnt, value)); - + RETURN_API_void(); } // Added 2005/11/21 (no SDK update): static void mm_CvarValue2(const edict_t *pEnt, int requestID, const char *cvarName, const char *value) { META_NEWAPI_HANDLE_void(FN_CVARVALUE2, pfnCvarValue2, pi2p, (pEnt, requestID, cvarName, value)); - + RETURN_API_void(); } // From SDK dlls/cbase.cpp: // "(wd)" indicates my comments on the functions -static DLL_FUNCTIONS gFunctionTable = +static DLL_FUNCTIONS gFunctionTable = { mm_GameDLLInit, //! pfnGameInit() Initialize the game (one-time call after loading of game .dll) mm_DispatchSpawn, //! pfnSpawn() @@ -363,7 +356,7 @@ static DLL_FUNCTIONS gFunctionTable = DLL_FUNCTIONS *g_pHookedDllFunctions = &gFunctionTable; // It's not clear what the difference is between GetAPI and GetAPI2; they -// both appear to return the exact same function table. +// both appear to return the exact same function table. // // Only one of them appears to be ever called, though. If the DLL provides // GetAPI2, the engine/hlds will call that, and will not call GetAPI. If @@ -381,33 +374,33 @@ DLL_FUNCTIONS *g_pHookedDllFunctions = &gFunctionTable; C_DLLEXPORT int GetEntityAPI(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion) { META_DEBUG(3, ("called: GetEntityAPI; version=%d", interfaceVersion)); - if(!pFunctionTable || metamod_not_loaded) { + if (!pFunctionTable || metamod_not_loaded) { META_WARNING("GetEntityAPI called with null pFunctionTable"); - return(FALSE); + return FALSE; } - else if(interfaceVersion != INTERFACE_VERSION) { + else if (interfaceVersion != INTERFACE_VERSION) { META_WARNING("GetEntityAPI version mismatch; requested=%d ours=%d", interfaceVersion, INTERFACE_VERSION); - return(FALSE); + return FALSE; } Q_memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS)); - return(TRUE); + return TRUE; } C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion) { META_DEBUG(3, ("called: GetEntityAPI2; version=%d", *interfaceVersion)); - if(!pFunctionTable || metamod_not_loaded) { + if (!pFunctionTable || metamod_not_loaded) { META_WARNING("GetEntityAPI2 called with null pFunctionTable"); - return(FALSE); + return FALSE; } - else if(*interfaceVersion != INTERFACE_VERSION) { + else if (*interfaceVersion != INTERFACE_VERSION) { META_WARNING("GetEntityAPI2 version mismatch; requested=%d ours=%d", *interfaceVersion, INTERFACE_VERSION); //! Tell engine what version we had, so it can figure out who is out of date. *interfaceVersion = INTERFACE_VERSION; - return(FALSE); + return FALSE; } Q_memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS)); - return(TRUE); + return TRUE; } @@ -434,26 +427,26 @@ static meta_new_dll_functions_t sNewFunctionTable( NEW_DLL_FUNCTIONS *g_pHookedNewDllFunctions = &sNewFunctionTable; -C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) +C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion) { META_DEBUG(6, ("called: GetNewDLLFunctions; version=%d", *interfaceVersion)); #if 0 // ~dvander - but then you can't use cvar querying on many mods... // Don't provide these functions to engine if gamedll doesn't provide // them. Otherwise, we're in the position of having to provide answers // we can't necessarily provide (for instance, ShouldCollide())... - if(!GameDLL.funcs.newapi_table) - return(FALSE); + if (!GameDLL.funcs.newapi_table) + return FALSE; #endif - if(!pNewFunctionTable) { + if (!pNewFunctionTable) { META_ERROR("GetNewDLLFunctions called with null pNewFunctionTable"); - return(FALSE); + return FALSE; } - else if(*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) { + else if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION) { META_ERROR("GetNewDLLFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, NEW_DLL_FUNCTIONS_VERSION); //! Tell engine what version we had, so it can figure out who is out of date. *interfaceVersion = NEW_DLL_FUNCTIONS_VERSION; - return(FALSE); + return FALSE; } sNewFunctionTable.copy_to(pNewFunctionTable); - return(TRUE); + return TRUE; } diff --git a/src/dllapi.h b/metamod/src/dllapi.h similarity index 99% rename from src/dllapi.h rename to metamod/src/dllapi.h index 18f6cb5..afce58d 100644 --- a/src/dllapi.h +++ b/metamod/src/dllapi.h @@ -75,7 +75,7 @@ typedef int (*FN_INCONSISTENTFILE) ( const edict_t *player, const char *filename typedef int (*FN_ALLOWLAGCOMPENSATION) ( void ); typedef void (*FN_ONFREEENTPRIVATEDATA) (edict_t *pEnt); -typedef void (*FN_GAMESHUTDOWN) (void); +typedef void (*FN_GAMESHUTDOWN) (); typedef int (*FN_SHOULDCOLLIDE) (edict_t *pentTouched, edict_t *pentOther); // Added 2005/08/11 (no SDK update): typedef void (*FN_CVARVALUE)(const edict_t *pEnt, const char *value); diff --git a/src/engine_api.cpp b/metamod/src/engine_api.cpp similarity index 86% rename from src/engine_api.cpp rename to metamod/src/engine_api.cpp index 5cf1463..abdc6c2 100644 --- a/src/engine_api.cpp +++ b/metamod/src/engine_api.cpp @@ -1,14 +1,4 @@ -#include // offsetof -#include // vsnprintf, etc -#include // va_start, etc -#include // alloca, etc -#include // always -#include "engine_api.h" // me -#include "metamod.h" // SETUP_API_CALLS, etc -#include "api_info.h" // dllapi_info, etc -#include "log_meta.h" // META_ERROR, etc -#include "osdep.h" // win32 vsnprintf, etc -#include "api_hook.h" +#include "precompiled.h" // Engine routines, functions returning "void". #define META_ENGINE_HANDLE_void(FN_TYPE, pfnName, pack_args_type, pfn_args) \ @@ -35,9 +25,9 @@ va_start(vargs, szFmt); \ len = safe_vsnprintf(strbuf, sizeof(strbuf), szFmt, vargs); \ va_end(vargs); \ - if((unsigned)len >= sizeof(strbuf)) { \ + if ((unsigned)len >= sizeof(strbuf)) { \ buf = (char *)malloc(len + 1); \ - if(buf) { \ + if (buf) { \ va_start(vargs, szFmt); \ safevoid_vsnprintf(buf, len + 1, szFmt, vargs); \ va_end(vargs); \ @@ -47,7 +37,7 @@ } \ } #define CLEAN_FORMATED_STRING() \ - if(buf != strbuf) \ + if (buf != strbuf) \ free(buf); #else #define MAKE_FORMATED_STRING(szFmt) \ @@ -56,7 +46,7 @@ va_start(ap, szFmt); \ safevoid_vsnprintf(buf, sizeof(buf), szFmt, ap); \ va_end(ap); - + #define CLEAN_FORMATED_STRING() #endif @@ -85,18 +75,22 @@ static int mm_PrecacheModel(const char *s) { META_ENGINE_HANDLE(int, 0, FN_PRECACHEMODEL, pfnPrecacheModel, p, (s)); RETURN_API(int) } -static int mm_PrecacheSound( const char *s) { + +static int mm_PrecacheSound(const char *s) { META_ENGINE_HANDLE(int, 0, FN_PRECACHESOUND, pfnPrecacheSound, p, (s)); RETURN_API(int) } + static void mm_SetModel(edict_t *e, const char *m) { META_ENGINE_HANDLE_void(FN_SETMODEL, pfnSetModel, 2p, (e, m)); RETURN_API_void() } + static int mm_ModelIndex(const char *m) { META_ENGINE_HANDLE(int, 0, FN_MODELINDEX, pfnModelIndex, p, (m)); RETURN_API(int) } + static int mm_ModelFrames(int modelIndex) { META_ENGINE_HANDLE(int, 0, FN_MODELFRAMES, pfnModelFrames, i, (modelIndex)); RETURN_API(int) @@ -106,14 +100,17 @@ static void mm_SetSize(edict_t *e, const float *rgflMin, const float *rgflMax) { META_ENGINE_HANDLE_void(FN_SETSIZE, pfnSetSize, 3p, (e, rgflMin, rgflMax)); RETURN_API_void() } + static void mm_ChangeLevel(const char *s1, const char *s2) { META_ENGINE_HANDLE_void(FN_CHANGELEVEL, pfnChangeLevel, 2p, (s1, s2)); RETURN_API_void() } + static void mm_GetSpawnParms(edict_t *ent) { META_ENGINE_HANDLE_void(FN_GETSPAWNPARMS, pfnGetSpawnParms, p, (ent)); RETURN_API_void() } + static void mm_SaveSpawnParms(edict_t *ent) { META_ENGINE_HANDLE_void(FN_SAVESPAWNPARMS, pfnSaveSpawnParms, p, (ent)); RETURN_API_void() @@ -123,18 +120,22 @@ static float mm_VecToYaw(const float *rgflVector) { META_ENGINE_HANDLE(float, 0.0, FN_VECTOYAW, pfnVecToYaw, p, (rgflVector)); RETURN_API(float) } + static void mm_VecToAngles(const float *rgflVectorIn, float *rgflVectorOut) { META_ENGINE_HANDLE_void(FN_VECTOANGLES, pfnVecToAngles, 2p, (rgflVectorIn, rgflVectorOut)); RETURN_API_void() } + static void mm_MoveToOrigin(edict_t *ent, const float *pflGoal, float dist, int iMoveType) { META_ENGINE_HANDLE_void(FN_MOVETOORIGIN, pfnMoveToOrigin, 2pfi, (ent, pflGoal, dist, iMoveType)); RETURN_API_void() } + static void mm_ChangeYaw(edict_t *ent) { META_ENGINE_HANDLE_void(FN_CHANGEYAW, pfnChangeYaw, p, (ent)); RETURN_API_void() } + static void mm_ChangePitch(edict_t *ent) { META_ENGINE_HANDLE_void(FN_CHANGEPITCH, pfnChangePitch, p, (ent)); RETURN_API_void() @@ -144,18 +145,22 @@ static edict_t *mm_FindEntityByString(edict_t *pEdictStartSearchAfter, const cha META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYBYSTRING, pfnFindEntityByString, 3p, (pEdictStartSearchAfter, pszField, pszValue)); RETURN_API(edict_t *) } + static int mm_GetEntityIllum(edict_t *pEnt) { META_ENGINE_HANDLE(int, 0, FN_GETENTITYILLUM, pfnGetEntityIllum, p, (pEnt)); RETURN_API(int) } + static edict_t *mm_FindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad) { META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYINSPHERE, pfnFindEntityInSphere, 2pf, (pEdictStartSearchAfter, org, rad)); RETURN_API(edict_t *) } + static edict_t *mm_FindClientInPVS(edict_t *pEdict) { META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDCLIENTINPVS, pfnFindClientInPVS, p, (pEdict)); RETURN_API(edict_t *) } + static edict_t *mm_EntitiesInPVS(edict_t *pplayer) { META_ENGINE_HANDLE(edict_t *, NULL, FN_ENTITIESINPVS, pfnEntitiesInPVS, p, (pplayer)); RETURN_API(edict_t *) @@ -165,19 +170,22 @@ static void mm_MakeVectors(const float *rgflVector) { META_ENGINE_HANDLE_void(FN_MAKEVECTORS, pfnMakeVectors, p, (rgflVector)); RETURN_API_void() } + static void mm_AngleVectors(const float *rgflVector, float *forward, float *right, float *up) { META_ENGINE_HANDLE_void(FN_ANGLEVECTORS, pfnAngleVectors, 4p, (rgflVector, forward, right, up)); RETURN_API_void() } -static edict_t *mm_CreateEntity(void) { +static edict_t *mm_CreateEntity() { META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATEENTITY, pfnCreateEntity, void, (VOID_ARG)); RETURN_API(edict_t *) } + static void mm_RemoveEntity(edict_t *e) { META_ENGINE_HANDLE_void(FN_REMOVEENTITY, pfnRemoveEntity, p, (e)); RETURN_API_void() } + static edict_t *mm_CreateNamedEntity(int className) { META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATENAMEDENTITY, pfnCreateNamedEntity, i, (className)); RETURN_API(edict_t *) @@ -187,10 +195,12 @@ static void mm_MakeStatic(edict_t *ent) { META_ENGINE_HANDLE_void(FN_MAKESTATIC, pfnMakeStatic, p, (ent)); RETURN_API_void() } + static int mm_EntIsOnFloor(edict_t *e) { META_ENGINE_HANDLE(int, 0, FN_ENTISONFLOOR, pfnEntIsOnFloor, p, (e)); RETURN_API(int) } + static int mm_DropToFloor(edict_t *e) { META_ENGINE_HANDLE(int, 0, FN_DROPTOFLOOR, pfnDropToFloor, p, (e)); RETURN_API(int) @@ -200,6 +210,7 @@ static int mm_WalkMove(edict_t *ent, float yaw, float dist, int iMode) { META_ENGINE_HANDLE(int, 0, FN_WALKMOVE, pfnWalkMove, p2fi, (ent, yaw, dist, iMode)); RETURN_API(int) } + static void mm_SetOrigin(edict_t *e, const float *rgflOrigin) { META_ENGINE_HANDLE_void(FN_SETORIGIN, pfnSetOrigin, 2p, (e, rgflOrigin)); RETURN_API_void() @@ -209,6 +220,7 @@ static void mm_EmitSound(edict_t *entity, int channel, const char *sample, float META_ENGINE_HANDLE_void(FN_EMITSOUND, pfnEmitSound, pip2f2i, (entity, channel, sample, volume, attenuation, fFlags, pitch)); RETURN_API_void() } + static void mm_EmitAmbientSound(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch) { META_ENGINE_HANDLE_void(FN_EMITAMBIENTSOUND, pfnEmitAmbientSound, 3p2f2i, (entity, pos, samp, vol, attenuation, fFlags, pitch)); RETURN_API_void() @@ -218,44 +230,53 @@ static void mm_TraceLine(const float *v1, const float *v2, int fNoMonsters, edic META_ENGINE_HANDLE_void(FN_TRACELINE, pfnTraceLine, 2pi2p, (v1, v2, fNoMonsters, pentToSkip, ptr)); RETURN_API_void() } + static void mm_TraceToss(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr) { META_ENGINE_HANDLE_void(FN_TRACETOSS, pfnTraceToss, 3p, (pent, pentToIgnore, ptr)); RETURN_API_void() } + static int mm_TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) { META_ENGINE_HANDLE(int, 0, FN_TRACEMONSTERHULL, pfnTraceMonsterHull, 3pi2p, (pEdict, v1, v2, fNoMonsters, pentToSkip, ptr)); RETURN_API(int) } + static void mm_TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr) { META_ENGINE_HANDLE_void(FN_TRACEHULL, pfnTraceHull, 2p2i2p, (v1, v2, fNoMonsters, hullNumber, pentToSkip, ptr)); RETURN_API_void() } + static void mm_TraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr) { META_ENGINE_HANDLE_void(FN_TRACEMODEL, pfnTraceModel, 2pi2p, (v1, v2, hullNumber, pent, ptr)); RETURN_API_void() } + static const char *mm_TraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2 ) { META_ENGINE_HANDLE(const char *, NULL, FN_TRACETEXTURE, pfnTraceTexture, 3p, (pTextureEntity, v1, v2)); RETURN_API(const char *) } + static void mm_TraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr) { META_ENGINE_HANDLE_void(FN_TRACESPHERE, pfnTraceSphere, 2pif2p, (v1, v2, fNoMonsters, radius, pentToSkip, ptr)); RETURN_API_void() } + static void mm_GetAimVector(edict_t *ent, float speed, float *rgflReturn) { META_ENGINE_HANDLE_void(FN_GETAIMVECTOR, pfnGetAimVector, pfp, (ent, speed, rgflReturn)); RETURN_API_void() } -static void mm_ServerCommand(const char *str) { +static void mm_ServerCommand(char *str) { META_ENGINE_HANDLE_void(FN_SERVERCOMMAND, pfnServerCommand, p, (str)); RETURN_API_void() } -static void mm_ServerExecute(void) { + +static void mm_ServerExecute() { META_ENGINE_HANDLE_void(FN_SERVEREXECUTE, pfnServerExecute, void, (VOID_ARG)); RETURN_API_void() } -static void mm_engClientCommand(edict_t *pEdict, const char *szFmt, ...) { + +static void mm_engClientCommand(edict_t *pEdict, char *szFmt, ...) { META_ENGINE_HANDLE_void_varargs(FN_CLIENTCOMMAND_ENG, pfnClientCommand, 2pV, pEdict, szFmt); RETURN_API_void() } @@ -264,14 +285,17 @@ static void mm_ParticleEffect(const float *org, const float *dir, float color, f META_ENGINE_HANDLE_void(FN_PARTICLEEFFECT, pfnParticleEffect, 2p2f, (org, dir, color, count)); RETURN_API_void() } -static void mm_LightStyle(int style, const char *val) { + +static void mm_LightStyle(int style, char *val) { META_ENGINE_HANDLE_void(FN_LIGHTSTYLE, pfnLightStyle, ip, (style, val)); RETURN_API_void() } + static int mm_DecalIndex(const char *name) { META_ENGINE_HANDLE(int, 0, FN_DECALINDEX, pfnDecalIndex, p, (name)); RETURN_API(int) } + static int mm_PointContents(const float *rgflVector) { META_ENGINE_HANDLE(int, 0, FN_POINTCONTENTS, pfnPointContents, p, (rgflVector)); RETURN_API(int) @@ -281,7 +305,8 @@ static void mm_MessageBegin(int msg_dest, int msg_type, const float *pOrigin, ed META_ENGINE_HANDLE_void(FN_MESSAGEBEGIN, pfnMessageBegin, 2i2p, (msg_dest, msg_type, pOrigin, ed)); RETURN_API_void() } -static void mm_MessageEnd(void) { + +static void mm_MessageEnd() { META_ENGINE_HANDLE_void(FN_MESSAGEEND, pfnMessageEnd, void, (VOID_ARG)); RETURN_API_void() } @@ -290,30 +315,37 @@ static void mm_WriteByte(int iValue) { META_ENGINE_HANDLE_void(FN_WRITEBYTE, pfnWriteByte, i, (iValue)); RETURN_API_void() } + static void mm_WriteChar(int iValue) { META_ENGINE_HANDLE_void(FN_WRITECHAR, pfnWriteChar, i, (iValue)); RETURN_API_void() } + static void mm_WriteShort(int iValue) { META_ENGINE_HANDLE_void(FN_WRITESHORT, pfnWriteShort, i, (iValue)); RETURN_API_void() } + static void mm_WriteLong(int iValue) { META_ENGINE_HANDLE_void(FN_WRITELONG, pfnWriteLong, i, (iValue)); RETURN_API_void() } + static void mm_WriteAngle(float flValue) { META_ENGINE_HANDLE_void(FN_WRITEANGLE, pfnWriteAngle, f, (flValue)); RETURN_API_void() } + static void mm_WriteCoord(float flValue) { META_ENGINE_HANDLE_void(FN_WRITECOORD, pfnWriteCoord, f, (flValue)); RETURN_API_void() } + static void mm_WriteString(const char *sz) { META_ENGINE_HANDLE_void(FN_WRITESTRING, pfnWriteString, p, (sz)); RETURN_API_void() } + static void mm_WriteEntity(int iValue) { META_ENGINE_HANDLE_void(FN_WRITEENTITY, pfnWriteEntity, i, (iValue)); RETURN_API_void() @@ -323,14 +355,17 @@ static void mm_CVarRegister(cvar_t *pCvar) { META_ENGINE_HANDLE_void(FN_CVARREGISTER, pfnCVarRegister, p, (pCvar)); RETURN_API_void() } + static float mm_CVarGetFloat(const char *szVarName) { META_ENGINE_HANDLE(float, 0.0, FN_CVARGETFLOAT, pfnCVarGetFloat, p, (szVarName)); RETURN_API(float) } + static const char *mm_CVarGetString(const char *szVarName) { META_ENGINE_HANDLE(const char *, NULL, FN_CVARGETSTRING, pfnCVarGetString, p, (szVarName)); RETURN_API(const char *) } + static void mm_CVarSetFloat(const char *szVarName, float flValue) { META_ENGINE_HANDLE_void(FN_CVARSETFLOAT, pfnCVarSetFloat, pf, (szVarName, flValue)); @@ -338,6 +373,7 @@ static void mm_CVarSetFloat(const char *szVarName, float flValue) { RETURN_API_void() } + static void mm_CVarSetString(const char *szVarName, const char *szValue) { META_ENGINE_HANDLE_void(FN_CVARSETSTRING, pfnCVarSetString, 2p, (szVarName, szValue)); @@ -350,27 +386,22 @@ static void mm_AlertMessage(ALERT_TYPE atype, const char *szFmt, ...) { META_ENGINE_HANDLE_void_varargs(FN_ALERTMESSAGE, pfnAlertMessage, ipV, atype, szFmt); RETURN_API_void() } -#ifdef HLSDK_3_2_OLD_EIFACE -static void mm_EngineFprintf(FILE *pfile, char *szFmt, ...) { -#else + static void mm_EngineFprintf(void *pfile, const char *szFmt, ...) { -#endif META_ENGINE_HANDLE_void_varargs(FN_ENGINEFPRINTF, pfnEngineFprintf, 2pV, pfile, szFmt); RETURN_API_void() } -#ifdef HLSDK_3_2_OLD_EIFACE -static void *mm_PvAllocEntPrivateData(edict_t *pEdict, long cb) { -#else static void *mm_PvAllocEntPrivateData(edict_t *pEdict, int32 cb) { -#endif META_ENGINE_HANDLE(void *, NULL, FN_PVALLOCENTPRIVATEDATA, pfnPvAllocEntPrivateData, pi, (pEdict, cb)); RETURN_API(void *) } + static void *mm_PvEntPrivateData(edict_t *pEdict) { META_ENGINE_HANDLE(void *, NULL, FN_PVENTPRIVATEDATA, pfnPvEntPrivateData, p, (pEdict)); RETURN_API(void *) } + static void mm_FreeEntPrivateData(edict_t *pEdict) { META_ENGINE_HANDLE_void(FN_FREEENTPRIVATEDATA, pfnFreeEntPrivateData, p, (pEdict)); RETURN_API_void() @@ -380,6 +411,7 @@ static const char *mm_SzFromIndex(int iString) { META_ENGINE_HANDLE(const char *, NULL, FN_SZFROMINDEX, pfnSzFromIndex, i, (iString)); RETURN_API(const char *) } + static int mm_AllocString(const char *szValue) { META_ENGINE_HANDLE(int, 0, FN_ALLOCSTRING, pfnAllocString, p, (szValue)); RETURN_API(int) @@ -389,26 +421,32 @@ static struct entvars_s *mm_GetVarsOfEnt(edict_t *pEdict) { META_ENGINE_HANDLE(struct entvars_s *, NULL, FN_GETVARSOFENT, pfnGetVarsOfEnt, p, (pEdict)); RETURN_API(struct entvars_s *) } + static edict_t *mm_PEntityOfEntOffset(int iEntOffset) { META_ENGINE_HANDLE(edict_t *, NULL, FN_PENTITYOFENTOFFSET, pfnPEntityOfEntOffset, i, (iEntOffset)); RETURN_API(edict_t *) } + static int mm_EntOffsetOfPEntity(const edict_t *pEdict) { META_ENGINE_HANDLE(int, 0, FN_ENTOFFSETOFPENTITY, pfnEntOffsetOfPEntity, p, (pEdict)); RETURN_API(int) } + static int mm_IndexOfEdict(const edict_t *pEdict) { META_ENGINE_HANDLE(int, 0, FN_INDEXOFEDICT, pfnIndexOfEdict, p, (pEdict)); RETURN_API(int) } + static edict_t *mm_PEntityOfEntIndex(int iEntIndex) { META_ENGINE_HANDLE(edict_t *, NULL, FN_PENTITYOFENTINDEX, pfnPEntityOfEntIndex, i, (iEntIndex)); RETURN_API(edict_t *) } + static edict_t *mm_FindEntityByVars(struct entvars_s *pvars) { META_ENGINE_HANDLE(edict_t *, NULL, FN_FINDENTITYBYVARS, pfnFindEntityByVars, p, (pvars)); RETURN_API(edict_t *) } + static void *mm_GetModelPtr(edict_t *pEdict) { META_ENGINE_HANDLE(void *, NULL, FN_GETMODELPTR, pfnGetModelPtr, p, (pEdict)); RETURN_API(void *) @@ -421,12 +459,12 @@ static int mm_RegUserMsg(const char *pszName, int iSize) { // Expand the macro, since we need to do extra work. /// RETURN_API(int) imsgid = GET_RET_CLASS(ret_val, int); - + // Add the msgid, name, and size to our saved list, if we haven't // already. nmsg=RegMsgs->find(imsgid); - if(nmsg) { - if(FStrEq(pszName, nmsg->name)) + if (nmsg) { + if (FStrEq(pszName, nmsg->name)) // This name/msgid pair was already registered. META_DEBUG(3, ("user message registered again: name=%s, msgid=%d", pszName, imsgid)); else @@ -435,34 +473,26 @@ static int mm_RegUserMsg(const char *pszName, int iSize) { } else RegMsgs->add(pszName, imsgid, iSize); - return(imsgid); + + return imsgid; } static void mm_AnimationAutomove(const edict_t *pEdict, float flTime) { META_ENGINE_HANDLE_void(FN_ANIMATIONAUTOMOVE, pfnAnimationAutomove, pf, (pEdict, flTime)); RETURN_API_void() } + static void mm_GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles ) { META_ENGINE_HANDLE_void(FN_GETBONEPOSITION, pfnGetBonePosition, pi2p, (pEdict, iBone, rgflOrigin, rgflAngles)); RETURN_API_void() } -#ifdef HLSDK_3_2_OLD_EIFACE -static unsigned long mm_FunctionFromName( const char *pName ) { - META_ENGINE_HANDLE(unsigned long, 0, FN_FUNCTIONFROMNAME, pfnFunctionFromName, p, (pName)); - RETURN_API(unsigned long) -} -#else -static uint32 mm_FunctionFromName( const char *pName ) { +static uint32 mm_FunctionFromName(const char *pName) { META_ENGINE_HANDLE(uint32, 0, FN_FUNCTIONFROMNAME, pfnFunctionFromName, p, (pName)); RETURN_API(uint32) } -#endif -#ifdef HLSDK_3_2_OLD_EIFACE -static const char *mm_NameForFunction( unsigned long function ) { -#else -static const char *mm_NameForFunction( uint32 function ) { -#endif + +static const char *mm_NameForFunction(uint32 function) { META_ENGINE_HANDLE(const char *, NULL, FN_NAMEFORFUNCTION, pfnNameForFunction, ui, (function)); RETURN_API(const char *) } @@ -472,6 +502,7 @@ static void mm_ClientPrintf( edict_t *pEdict, PRINT_TYPE ptype, const char *szMs META_ENGINE_HANDLE_void(FN_CLIENTPRINTF, pfnClientPrintf, pip, (pEdict, ptype, szMsg)); RETURN_API_void() } + static void mm_ServerPrint( const char *szMsg ) { META_ENGINE_HANDLE_void(FN_SERVERPRINT, pfnServerPrint, p, (szMsg)); RETURN_API_void() @@ -482,10 +513,12 @@ static const char *mm_Cmd_Args( void ) { META_ENGINE_HANDLE(const char *, NULL, FN_CMD_ARGS, pfnCmd_Args, void, (VOID_ARG)); RETURN_API(const char *) } + static const char *mm_Cmd_Argv( int argc ) { META_ENGINE_HANDLE(const char *, NULL, FN_CMD_ARGV, pfnCmd_Argv, i, (argc)); RETURN_API(const char *) } + static int mm_Cmd_Argc( void ) { META_ENGINE_HANDLE(int, 0, FN_CMD_ARGC, pfnCmd_Argc, void, (VOID_ARG)); RETURN_API(int) @@ -500,30 +533,27 @@ static void mm_CRC32_Init(CRC32_t *pulCRC) { META_ENGINE_HANDLE_void(FN_CRC32_INIT, pfnCRC32_Init, p, (pulCRC)); RETURN_API_void() } + static void mm_CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len) { META_ENGINE_HANDLE_void(FN_CRC32_PROCESSBUFFER, pfnCRC32_ProcessBuffer, 2pi, (pulCRC, p, len)); RETURN_API_void() } + static void mm_CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch) { META_ENGINE_HANDLE_void(FN_CRC32_PROCESSBYTE, pfnCRC32_ProcessByte, puc, (pulCRC, ch)); RETURN_API_void() } + static CRC32_t mm_CRC32_Final(CRC32_t pulCRC) { META_ENGINE_HANDLE(CRC32_t, 0, FN_CRC32_FINAL, pfnCRC32_Final, ul, (pulCRC)); RETURN_API(CRC32_t) } -#ifdef HLSDK_3_2_OLD_EIFACE -static long mm_RandomLong(long lLow, long lHigh) { - META_ENGINE_HANDLE(long, 0, FN_RANDOMLONG, pfnRandomLong, 2i, (lLow, lHigh)); - RETURN_API(long) -} -#else static int32 mm_RandomLong(int32 lLow, int32 lHigh) { META_ENGINE_HANDLE(int32, 0, FN_RANDOMLONG, pfnRandomLong, 2i, (lLow, lHigh)); RETURN_API(int32) } -#endif + static float mm_RandomFloat(float flLow, float flHigh) { META_ENGINE_HANDLE(float, 0.0, FN_RANDOMFLOAT, pfnRandomFloat, 2f, (flLow, flHigh)); RETURN_API(float) @@ -533,19 +563,22 @@ static void mm_SetView(const edict_t *pClient, const edict_t *pViewent ) { META_ENGINE_HANDLE_void(FN_SETVIEW, pfnSetView, 2p, (pClient, pViewent)); RETURN_API_void() } + static float mm_Time( void ) { META_ENGINE_HANDLE(float, 0.0, FN_TIME, pfnTime, void, (VOID_ARG)); RETURN_API(float) } + static void mm_CrosshairAngle(const edict_t *pClient, float pitch, float yaw) { META_ENGINE_HANDLE_void(FN_CROSSHAIRANGLE, pfnCrosshairAngle, p2f, (pClient, pitch, yaw)); RETURN_API_void() } -static byte * mm_LoadFileForMe(const char *filename, int *pLength) { +static byte * mm_LoadFileForMe(char *filename, int *pLength) { META_ENGINE_HANDLE(byte *, NULL, FN_LOADFILEFORME, pfnLoadFileForMe, 2p, (filename, pLength)); RETURN_API(byte *) } + static void mm_FreeFile(void *buffer) { META_ENGINE_HANDLE_void(FN_FREEFILE, pfnFreeFile, p, (buffer)); RETURN_API_void() @@ -556,36 +589,44 @@ static void mm_EndSection(const char *pszSectionName) { META_ENGINE_HANDLE_void(FN_ENDSECTION, pfnEndSection, p, (pszSectionName)); RETURN_API_void() } + static int mm_CompareFileTime(char *filename1, char *filename2, int *iCompare) { META_ENGINE_HANDLE(int, 0, FN_COMPAREFILETIME, pfnCompareFileTime, 3p, (filename1, filename2, iCompare)); RETURN_API(int) } + static void mm_GetGameDir(char *szGetGameDir) { META_ENGINE_HANDLE_void(FN_GETGAMEDIR, pfnGetGameDir, p, (szGetGameDir)); RETURN_API_void() } + static void mm_Cvar_RegisterVariable(cvar_t *variable) { META_ENGINE_HANDLE_void(FN_CVAR_REGISTERVARIABLE, pfnCvar_RegisterVariable, p, (variable)); RETURN_API_void() } + static void mm_FadeClientVolume(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds) { META_ENGINE_HANDLE_void(FN_FADECLIENTVOLUME, pfnFadeClientVolume, p4i, (pEdict, fadePercent, fadeOutSeconds, holdTime, fadeInSeconds)); RETURN_API_void() } -static void mm_SetClientMaxspeed(const edict_t *pEdict, float fNewMaxspeed) { + +static void mm_SetClientMaxspeed(edict_t *pEdict, float fNewMaxspeed) { META_ENGINE_HANDLE_void(FN_SETCLIENTMAXSPEED, pfnSetClientMaxspeed, pf, (pEdict, fNewMaxspeed)); RETURN_API_void() } + //! returns NULL if fake client can't be created static edict_t * mm_CreateFakeClient(const char *netname) { META_ENGINE_HANDLE(edict_t *, NULL, FN_CREATEFAKECLIENT, pfnCreateFakeClient, p, (netname)); RETURN_API(edict_t *) } + static void mm_RunPlayerMove(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ) { META_ENGINE_HANDLE_void(FN_RUNPLAYERMOVE, pfnRunPlayerMove, 2p3fus2uc, (fakeclient, viewangles, forwardmove, sidemove, upmove, buttons, impulse, msec)); RETURN_API_void() } -static int mm_NumberOfEntities(void) { + +static int mm_NumberOfEntities() { META_ENGINE_HANDLE(int, 0, FN_NUMBEROFENTITIES, pfnNumberOfEntities, void, (VOID_ARG)); RETURN_API(int) } @@ -595,50 +636,60 @@ static char *mm_GetInfoKeyBuffer(edict_t *e) { META_ENGINE_HANDLE(char *, NULL, FN_GETINFOKEYBUFFER, pfnGetInfoKeyBuffer, p, (e)); RETURN_API(char *) } + static char *mm_InfoKeyValue(char *infobuffer, const char *key) { META_ENGINE_HANDLE(char *, NULL, FN_INFOKEYVALUE, pfnInfoKeyValue, 2p, (infobuffer, key)); RETURN_API(char *) } + static void mm_SetKeyValue(char *infobuffer, const char *key, const char *value) { META_ENGINE_HANDLE_void(FN_SETKEYVALUE, pfnSetKeyValue, 3p, (infobuffer, key, value)); RETURN_API_void() } + static void mm_SetClientKeyValue(int clientIndex, char *infobuffer, const char *key, const char *value) { META_ENGINE_HANDLE_void(FN_SETCLIENTKEYVALUE, pfnSetClientKeyValue, i3p, (clientIndex, infobuffer, key, value)); RETURN_API_void() } -static int mm_IsMapValid(const char *filename) { +static int mm_IsMapValid(char *filename) { META_ENGINE_HANDLE(int, 0, FN_ISMAPVALID, pfnIsMapValid, p, (filename)); RETURN_API(int) } + static void mm_StaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ) { META_ENGINE_HANDLE_void(FN_STATICDECAL, pfnStaticDecal, p3i, (origin, decalIndex, entityIndex, modelIndex)); RETURN_API_void() } -static int mm_PrecacheGeneric(const char *s) { + +static int mm_PrecacheGeneric(char *s) { META_ENGINE_HANDLE(int, 0, FN_PRECACHEGENERIC, pfnPrecacheGeneric, p, (s)); RETURN_API(int) } + //! returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients static int mm_GetPlayerUserId(edict_t *e ) { META_ENGINE_HANDLE(int, 0, FN_GETPLAYERUSERID, pfnGetPlayerUserId, p, (e)); RETURN_API(int) } -static void mm_BuildSoundMsg(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) + +static void mm_BuildSoundMsg(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) { META_ENGINE_HANDLE_void(FN_BUILDSOUNDMSG, pfnBuildSoundMsg, pip2f4i2p, (entity, channel, sample, volume, attenuation, fFlags, pitch, msg_dest, msg_type, pOrigin, ed)); RETURN_API_void() } + //! is this a dedicated server? -static int mm_IsDedicatedServer(void) { +static int mm_IsDedicatedServer() { META_ENGINE_HANDLE(int, 0, FN_ISDEDICATEDSERVER, pfnIsDedicatedServer, void, (VOID_ARG)); RETURN_API(int) } + static cvar_t *mm_CVarGetPointer(const char *szVarName) { META_ENGINE_HANDLE(cvar_t *, NULL, FN_CVARGETPOINTER, pfnCVarGetPointer, p, (szVarName)); RETURN_API(cvar_t *) } + //! returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients static unsigned int mm_GetPlayerWONId(edict_t *e) { META_ENGINE_HANDLE(unsigned int, 0, FN_GETPLAYERWONID, pfnGetPlayerWONId, p, (e)); @@ -650,22 +701,27 @@ static void mm_Info_RemoveKey( char *s, const char *key ) { META_ENGINE_HANDLE_void(FN_INFO_REMOVEKEY, pfnInfo_RemoveKey, 2p, (s, key)); RETURN_API_void() } + static const char *mm_GetPhysicsKeyValue( const edict_t *pClient, const char *key ) { META_ENGINE_HANDLE(const char *, NULL, FN_GETPHYSICSKEYVALUE, pfnGetPhysicsKeyValue, 2p, (pClient, key)); RETURN_API(const char *) } + static void mm_SetPhysicsKeyValue( const edict_t *pClient, const char *key, const char *value ) { META_ENGINE_HANDLE_void(FN_SETPHYSICSKEYVALUE, pfnSetPhysicsKeyValue, 3p, (pClient, key, value)); RETURN_API_void() } + static const char *mm_GetPhysicsInfoString( const edict_t *pClient ) { META_ENGINE_HANDLE(const char *, NULL, FN_GETPHYSICSINFOSTRING, pfnGetPhysicsInfoString, p, (pClient)); RETURN_API(const char *) } + static unsigned short mm_PrecacheEvent( int type, const char *psz ) { META_ENGINE_HANDLE(unsigned short, 0, FN_PRECACHEEVENT, pfnPrecacheEvent, ip, (type, psz)); RETURN_API(unsigned short) } + static void mm_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) { META_ENGINE_HANDLE_void(FN_PLAYBACKEVENT, pfnPlaybackEvent, ipusf2p2f4i, (flags, pInvoker, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2)); RETURN_API_void() @@ -675,12 +731,13 @@ static unsigned char *mm_SetFatPVS( float *org ) { META_ENGINE_HANDLE(unsigned char *, 0, FN_SETFATPVS, pfnSetFatPVS, p, (org)); RETURN_API(unsigned char *) } + static unsigned char *mm_SetFatPAS( float *org ) { META_ENGINE_HANDLE(unsigned char *, 0, FN_SETFATPAS, pfnSetFatPAS, p, (org)); RETURN_API(unsigned char *) } -static int mm_CheckVisibility( const edict_t *entity, unsigned char *pset ) { +static int mm_CheckVisibility(edict_t *entity, unsigned char *pset ) { META_ENGINE_HANDLE(int, 0, FN_CHECKVISIBILITY, pfnCheckVisibility, 2p, (entity, pset)); RETURN_API(int) } @@ -689,30 +746,37 @@ static void mm_DeltaSetField( struct delta_s *pFields, const char *fieldname ) { META_ENGINE_HANDLE_void(FN_DELTASETFIELD, pfnDeltaSetField, 2p, (pFields, fieldname)); RETURN_API_void() } + static void mm_DeltaUnsetField( struct delta_s *pFields, const char *fieldname ) { META_ENGINE_HANDLE_void(FN_DELTAUNSETFIELD, pfnDeltaUnsetField, 2p, (pFields, fieldname)); RETURN_API_void() } -static void mm_DeltaAddEncoder( const char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ) { + +static void mm_DeltaAddEncoder(char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ) { META_ENGINE_HANDLE_void(FN_DELTAADDENCODER, pfnDeltaAddEncoder, 2p, (name, (void*)conditionalencode)); RETURN_API_void() } + static int mm_GetCurrentPlayer( void ) { META_ENGINE_HANDLE(int, 0, FN_GETCURRENTPLAYER, pfnGetCurrentPlayer, void, (VOID_ARG)); RETURN_API(int) } + static int mm_CanSkipPlayer( const edict_t *player ) { META_ENGINE_HANDLE(int, 0, FN_CANSKIPPLAYER, pfnCanSkipPlayer, p, (player)); RETURN_API(int) } + static int mm_DeltaFindField( struct delta_s *pFields, const char *fieldname ) { META_ENGINE_HANDLE(int, 0, FN_DELTAFINDFIELD, pfnDeltaFindField, 2p, (pFields, fieldname)); RETURN_API(int) } + static void mm_DeltaSetFieldByIndex( struct delta_s *pFields, int fieldNumber ) { META_ENGINE_HANDLE_void(FN_DELTASETFIELDBYINDEX, pfnDeltaSetFieldByIndex, pi, (pFields, fieldNumber)); RETURN_API_void() } + static void mm_DeltaUnsetFieldByIndex( struct delta_s *pFields, int fieldNumber ) { META_ENGINE_HANDLE_void(FN_DELTAUNSETFIELDBYINDEX, pfnDeltaUnsetFieldByIndex, pi, (pFields, fieldNumber)); RETURN_API_void() @@ -727,6 +791,7 @@ static int mm_engCreateInstancedBaseline( int classname, struct entity_state_s * META_ENGINE_HANDLE(int, 0, FN_CREATEINSTANCEDBASELINE, pfnCreateInstancedBaseline, ip, (classname, baseline)); RETURN_API(int) } + static void mm_Cvar_DirectSet( struct cvar_s *var, const char *value ) { META_ENGINE_HANDLE_void(FN_CVAR_DIRECTSET, pfnCvar_DirectSet, 2p, (var, value)); @@ -743,12 +808,12 @@ static void mm_ForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const RETURN_API_void() } -static void mm_GetPlayerStats( const edict_t *pClient, int *ping, int *packet_loss ) { +static void mm_GetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss ) { META_ENGINE_HANDLE_void(FN_GETPLAYERSTATS, pfnGetPlayerStats, 3p, (pClient, ping, packet_loss)); RETURN_API_void() } -static void mm_AddServerCommand( const char *cmd_name, void (*function) (void) ) { +static void mm_AddServerCommand(char *cmd_name, void (*function) () ) { META_ENGINE_HANDLE_void(FN_ADDSERVERCOMMAND, pfnAddServerCommand, 2p, (cmd_name, (void*)function)); RETURN_API_void() } @@ -761,6 +826,7 @@ static qboolean mm_Voice_GetClientListening(int iReceiver, int iSender) { META_ENGINE_HANDLE(qboolean, false, FN_VOICE_GETCLIENTLISTENING, pfnVoice_GetClientListening, 2i, (iReceiver, iSender)); RETURN_API(qboolean) } + static qboolean mm_Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen) { META_ENGINE_HANDLE(qboolean, false, FN_VOICE_SETCLIENTLISTENING, pfnVoice_SetClientListening, 3i, (iReceiver, iSender, bListen)); RETURN_API(qboolean) @@ -774,7 +840,6 @@ static const char *mm_GetPlayerAuthId(edict_t *e) { } // Added 2003/11/10 (no SDK update): - static sequenceEntry_s *mm_SequenceGet(const char *fileName, const char *entryName) { META_ENGINE_HANDLE(sequenceEntry_s *, NULL, FN_SEQUENCEGET, pfnSequenceGet, 2p, (fileName, entryName)); RETURN_API(sequenceEntry_s *) @@ -785,7 +850,7 @@ static sentenceEntry_s *mm_SequencePickSentence(const char *groupName, int pickM RETURN_API(sentenceEntry_s *) } -static int mm_GetFileSize(const char *filename) { +static int mm_GetFileSize(char *filename) { META_ENGINE_HANDLE(int, 0, FN_GETFILESIZE, pfnGetFileSize, p, (filename)); RETURN_API(int) } @@ -795,7 +860,7 @@ static unsigned int mm_GetApproxWavePlayLen(const char *filepath) { RETURN_API(unsigned int) } -static int mm_IsCareerMatch(void) { +static int mm_IsCareerMatch() { META_ENGINE_HANDLE(int, 0, FN_ISCAREERMATCH, pfnIsCareerMatch, void, (VOID_ARG)); RETURN_API(int) } @@ -825,7 +890,7 @@ static void mm_ConstructTutorMessageDecayBuffer(int *buffer, int bufferLength) { RETURN_API_void() } -static void mm_ResetTutorMessageDecayData(void) { +static void mm_ResetTutorMessageDecayData() { META_ENGINE_HANDLE_void(FN_RESETTUTORMESSAGEDECAYDATA, pfnResetTutorMessageDecayData, void, (VOID_ARG)); RETURN_API_void() } @@ -833,14 +898,14 @@ static void mm_ResetTutorMessageDecayData(void) { // Added 2005/08/11 (no SDK update): static void mm_QueryClientCvarValue(const edict_t *player, const char *cvarName) { static mBOOL s_check = mFALSE; - + //Engine version didn't change when this API was added. Check if the pointer is valid. if (!s_check && g_engfuncs.pfnQueryClientCvarValue && !IS_VALID_PTR((void * )g_engfuncs.pfnQueryClientCvarValue)) { g_engfuncs.pfnQueryClientCvarValue = NULL; s_check = mTRUE; } - + META_ENGINE_HANDLE_void(FN_QUERYCLIENTCVARVALUE, pfnQueryClientCvarValue, 2p, (player, cvarName)); RETURN_API_void() } @@ -848,34 +913,33 @@ static void mm_QueryClientCvarValue(const edict_t *player, const char *cvarName) // Added 2005/11/21 (no SDK update): static void mm_QueryClientCvarValue2(const edict_t *player, const char *cvarName, int requestID) { static mBOOL s_check = mFALSE; - + //Engine version didn't change when this API was added. Check if the pointer is valid. if (!s_check && g_engfuncs.pfnQueryClientCvarValue2 && !IS_VALID_PTR((void * )g_engfuncs.pfnQueryClientCvarValue2)) { g_engfuncs.pfnQueryClientCvarValue2 = NULL; s_check = mTRUE; } - + META_ENGINE_HANDLE_void(FN_QUERYCLIENTCVARVALUE2, pfnQueryClientCvarValue2, 2pi, (player, cvarName, requestID)); RETURN_API_void() } // Added 2009/06/19 (no SDK update): -static int mm_CheckParm(const char *pchCmdLineToken, char **pchNextVal) { +static int mm_EngCheckParm(const char *pchCmdLineToken, char **pchNextVal) { static mBOOL s_check = mFALSE; //Engine version didn't change when this API was added. Check if the pointer is valid. - if (!s_check && g_engfuncs.pfnCheckParm && - !IS_VALID_PTR((void * )g_engfuncs.pfnCheckParm)) { - g_engfuncs.pfnCheckParm = NULL; + if (!s_check && g_engfuncs.pfnEngCheckParm && !IS_VALID_PTR((void *)g_engfuncs.pfnEngCheckParm)) { + g_engfuncs.pfnEngCheckParm = NULL; s_check = mTRUE; } - META_ENGINE_HANDLE(int, 0, FN_ENGCHECKPARM, pfnCheckParm, 2p, (pchCmdLineToken, pchNextVal)); + META_ENGINE_HANDLE(int, 0, FN_ENGCHECKPARM, pfnEngCheckParm, 2p, (pchCmdLineToken, pchNextVal)); RETURN_API(int) } -meta_enginefuncs_t meta_engfuncs ( +meta_enginefuncs_t meta_engfuncs( &mm_PrecacheModel, // pfnPrecacheModel() &mm_PrecacheSound, // pfnPrecacheSound() &mm_SetModel, // pfnSetModel() @@ -893,10 +957,10 @@ meta_enginefuncs_t meta_engfuncs ( &mm_ChangeYaw, // pfnChangeYaw() &mm_ChangePitch, // pfnChangePitch() - &mm_FindEntityByString, // pfnFindEntityByString() + &mm_FindEntityByString, // pfnFindEntityByString() &mm_GetEntityIllum, // pfnGetEntityIllum() - &mm_FindEntityInSphere, // pfnFindEntityInSphere() - &mm_FindClientInPVS, // pfnFindClientInPVS() + &mm_FindEntityInSphere, // pfnFindEntityInSphere() + &mm_FindClientInPVS, // pfnFindClientInPVS() &mm_EntitiesInPVS, // pfnEntitiesInPVS() &mm_MakeVectors, // pfnMakeVectors() @@ -904,7 +968,7 @@ meta_enginefuncs_t meta_engfuncs ( &mm_CreateEntity, // pfnCreateEntity() &mm_RemoveEntity, // pfnRemoveEntity() - &mm_CreateNamedEntity, // pfnCreateNamedEntity() + &mm_CreateNamedEntity, // pfnCreateNamedEntity() &mm_MakeStatic, // pfnMakeStatic() &mm_EntIsOnFloor, // pfnEntIsOnFloor() @@ -914,11 +978,11 @@ meta_enginefuncs_t meta_engfuncs ( &mm_SetOrigin, // pfnSetOrigin() &mm_EmitSound, // pfnEmitSound() - &mm_EmitAmbientSound, // pfnEmitAmbientSound() + &mm_EmitAmbientSound, // pfnEmitAmbientSound() &mm_TraceLine, // pfnTraceLine() &mm_TraceToss, // pfnTraceToss() - &mm_TraceMonsterHull, // pfnTraceMonsterHull() + &mm_TraceMonsterHull, // pfnTraceMonsterHull() &mm_TraceHull, // pfnTraceHull() &mm_TraceModel, // pfnTraceModel() &mm_TraceTexture, // pfnTraceTexture() @@ -927,7 +991,7 @@ meta_enginefuncs_t meta_engfuncs ( &mm_ServerCommand, // pfnServerCommand() &mm_ServerExecute, // pfnServerExecute() - &mm_engClientCommand, // pfnClientCommand() // D'oh, ClientCommand in dllapi too. + &mm_engClientCommand, // pfnClientCommand() // D'oh, ClientCommand in dllapi too. &mm_ParticleEffect, // pfnParticleEffect() &mm_LightStyle, // pfnLightStyle() @@ -955,136 +1019,132 @@ meta_enginefuncs_t meta_engfuncs ( &mm_AlertMessage, // pfnAlertMessage() &mm_EngineFprintf, // pfnEngineFprintf() - &mm_PvAllocEntPrivateData, // pfnPvAllocEntPrivateData() - &mm_PvEntPrivateData, // pfnPvEntPrivateData() - &mm_FreeEntPrivateData, // pfnFreeEntPrivateData() + &mm_PvAllocEntPrivateData, // pfnPvAllocEntPrivateData() + &mm_PvEntPrivateData, // pfnPvEntPrivateData() + &mm_FreeEntPrivateData, // pfnFreeEntPrivateData() &mm_SzFromIndex, // pfnSzFromIndex() &mm_AllocString, // pfnAllocString() &mm_GetVarsOfEnt, // pfnGetVarsOfEnt() - &mm_PEntityOfEntOffset, // pfnPEntityOfEntOffset() - &mm_EntOffsetOfPEntity, // pfnEntOffsetOfPEntity() + &mm_PEntityOfEntOffset, // pfnPEntityOfEntOffset() + &mm_EntOffsetOfPEntity, // pfnEntOffsetOfPEntity() &mm_IndexOfEdict, // pfnIndexOfEdict() - &mm_PEntityOfEntIndex, // pfnPEntityOfEntIndex() - &mm_FindEntityByVars, // pfnFindEntityByVars() + &mm_PEntityOfEntIndex, // pfnPEntityOfEntIndex() + &mm_FindEntityByVars, // pfnFindEntityByVars() &mm_GetModelPtr, // pfnGetModelPtr() &mm_RegUserMsg, // pfnRegUserMsg() - &mm_AnimationAutomove, // pfnAnimationAutomove() - &mm_GetBonePosition, // pfnGetBonePosition() + &mm_AnimationAutomove, // pfnAnimationAutomove() + &mm_GetBonePosition, // pfnGetBonePosition() - &mm_FunctionFromName, // pfnFunctionFromName() - &mm_NameForFunction, // pfnNameForFunction() + &mm_FunctionFromName, // pfnFunctionFromName() + &mm_NameForFunction, // pfnNameForFunction() &mm_ClientPrintf, // pfnClientPrintf() //! JOHN: engine callbacks so game DLL can print messages to individual clients &mm_ServerPrint, // pfnServerPrint() - &mm_Cmd_Args, // pfnCmd_Args() //! these 3 added - &mm_Cmd_Argv, // pfnCmd_Argv() //! so game DLL can easily + &mm_Cmd_Args, // pfnCmd_Args() //! these 3 added + &mm_Cmd_Argv, // pfnCmd_Argv() //! so game DLL can easily &mm_Cmd_Argc, // pfnCmd_Argc() //! access client 'cmd' strings &mm_GetAttachment, // pfnGetAttachment() &mm_CRC32_Init, // pfnCRC32_Init() - &mm_CRC32_ProcessBuffer, // pfnCRC32_ProcessBuffer() - &mm_CRC32_ProcessByte, // pfnCRC32_ProcessByte() + &mm_CRC32_ProcessBuffer, // pfnCRC32_ProcessBuffer() + &mm_CRC32_ProcessByte, // pfnCRC32_ProcessByte() &mm_CRC32_Final, // pfnCRC32_Final() &mm_RandomLong, // pfnRandomLong() &mm_RandomFloat, // pfnRandomFloat() &mm_SetView, // pfnSetView() - &mm_Time, // pfnTime() + &mm_Time, // pfnTime() &mm_CrosshairAngle, // pfnCrosshairAngle() &mm_LoadFileForMe, // pfnLoadFileForMe() &mm_FreeFile, // pfnFreeFile() &mm_EndSection, // pfnEndSection() //! trigger_endsection - &mm_CompareFileTime, // pfnCompareFileTime() + &mm_CompareFileTime, // pfnCompareFileTime() &mm_GetGameDir, // pfnGetGameDir() - &mm_Cvar_RegisterVariable, // pfnCvar_RegisterVariable() - &mm_FadeClientVolume, // pfnFadeClientVolume() - &mm_SetClientMaxspeed, // pfnSetClientMaxspeed() - &mm_CreateFakeClient, // pfnCreateFakeClient() //! returns NULL if fake client can't be created + &mm_Cvar_RegisterVariable, // pfnCvar_RegisterVariable() + &mm_FadeClientVolume, // pfnFadeClientVolume() + &mm_SetClientMaxspeed, // pfnSetClientMaxspeed() + &mm_CreateFakeClient, // pfnCreateFakeClient() //! returns NULL if fake client can't be created &mm_RunPlayerMove, // pfnRunPlayerMove() - &mm_NumberOfEntities, // pfnNumberOfEntities() + &mm_NumberOfEntities, // pfnNumberOfEntities() - &mm_GetInfoKeyBuffer, // pfnGetInfoKeyBuffer() //! passing in NULL gets the serverinfo + &mm_GetInfoKeyBuffer, // pfnGetInfoKeyBuffer() //! passing in NULL gets the serverinfo &mm_InfoKeyValue, // pfnInfoKeyValue() &mm_SetKeyValue, // pfnSetKeyValue() - &mm_SetClientKeyValue, // pfnSetClientKeyValue() + &mm_SetClientKeyValue, // pfnSetClientKeyValue() &mm_IsMapValid, // pfnIsMapValid() &mm_StaticDecal, // pfnStaticDecal() - &mm_PrecacheGeneric, // pfnPrecacheGeneric() - &mm_GetPlayerUserId, // pfnGetPlayerUserId() //! returns the server assigned userid for this player. + &mm_PrecacheGeneric, // pfnPrecacheGeneric() + &mm_GetPlayerUserId, // pfnGetPlayerUserId() //! returns the server assigned userid for this player. &mm_BuildSoundMsg, // pfnBuildSoundMsg() - &mm_IsDedicatedServer, // pfnIsDedicatedServer() //! is this a dedicated server? + &mm_IsDedicatedServer, // pfnIsDedicatedServer() //! is this a dedicated server? &mm_CVarGetPointer, // pfnCVarGetPointer() &mm_GetPlayerWONId, // pfnGetPlayerWONId() //! returns the server assigned WONid for this player. //! YWB 8/1/99 TFF Physics additions &mm_Info_RemoveKey, // pfnInfo_RemoveKey() - &mm_GetPhysicsKeyValue, // pfnGetPhysicsKeyValue() - &mm_SetPhysicsKeyValue, // pfnSetPhysicsKeyValue() - &mm_GetPhysicsInfoString, // pfnGetPhysicsInfoString() + &mm_GetPhysicsKeyValue, // pfnGetPhysicsKeyValue() + &mm_SetPhysicsKeyValue, // pfnSetPhysicsKeyValue() + &mm_GetPhysicsInfoString, // pfnGetPhysicsInfoString() &mm_PrecacheEvent, // pfnPrecacheEvent() &mm_PlaybackEvent, // pfnPlaybackEvent() - &mm_SetFatPVS, // pfnSetFatPVS() &mm_SetFatPAS, // pfnSetFatPAS() - - &mm_CheckVisibility, // pfnCheckVisibility() - + &mm_CheckVisibility, // pfnCheckVisibility() &mm_DeltaSetField, // pfnDeltaSetField() - &mm_DeltaUnsetField, // pfnDeltaUnsetField() - &mm_DeltaAddEncoder, // pfnDeltaAddEncoder() - &mm_GetCurrentPlayer, // pfnGetCurrentPlayer() + &mm_DeltaUnsetField, // pfnDeltaUnsetField() + &mm_DeltaAddEncoder, // pfnDeltaAddEncoder() + &mm_GetCurrentPlayer, // pfnGetCurrentPlayer() &mm_CanSkipPlayer, // pfnCanSkipPlayer() &mm_DeltaFindField, // pfnDeltaFindField() - &mm_DeltaSetFieldByIndex, // pfnDeltaSetFieldByIndex() - &mm_DeltaUnsetFieldByIndex, // pfnDeltaUnsetFieldByIndex() + &mm_DeltaSetFieldByIndex, // pfnDeltaSetFieldByIndex() + &mm_DeltaUnsetFieldByIndex, // pfnDeltaUnsetFieldByIndex() &mm_SetGroupMask, // pfnSetGroupMask() - &mm_engCreateInstancedBaseline, // pfnCreateInstancedBaseline() // D'oh, CreateInstancedBaseline in dllapi too. + &mm_engCreateInstancedBaseline, // pfnCreateInstancedBaseline() // D'oh, CreateInstancedBaseline in dllapi too. &mm_Cvar_DirectSet, // pfnCvar_DirectSet() - &mm_ForceUnmodified, // pfnForceUnmodified() - + &mm_ForceUnmodified, // pfnForceUnmodified() &mm_GetPlayerStats, // pfnGetPlayerStats() - &mm_AddServerCommand, // pfnAddServerCommand() + &mm_AddServerCommand, // pfnAddServerCommand() // Added in SDK 2l2: - &mm_Voice_GetClientListening, // pfnVoice_GetClientListening() - &mm_Voice_SetClientListening, // pfnVoice_SetClientListening() + &mm_Voice_GetClientListening, // pfnVoice_GetClientListening() + &mm_Voice_SetClientListening, // pfnVoice_SetClientListening() // Added for HL 1109 (no SDK update): &mm_GetPlayerAuthId, // pfnGetPlayerAuthId() // Added 2003/11/10 (no SDK update): - &mm_SequenceGet, // pfnSequenceGet() - &mm_SequencePickSentence, // pfnSequencePickSentence() - &mm_GetFileSize, // pfnGetFileSize() - &mm_GetApproxWavePlayLen, // pfnGetApproxWavePlayLen() - &mm_IsCareerMatch, // pfnIsCareerMatch() + &mm_SequenceGet, // pfnSequenceGet() + &mm_SequencePickSentence, // pfnSequencePickSentence() + &mm_GetFileSize, // pfnGetFileSize() + &mm_GetApproxWavePlayLen, // pfnGetApproxWavePlayLen() + &mm_IsCareerMatch, // pfnIsCareerMatch() &mm_GetLocalizedStringLength, // pfnGetLocalizedStringLength() - &mm_RegisterTutorMessageShown, // pfnRegisterTutorMessageShown() - &mm_GetTimesTutorMessageShown, // pfnGetTimesTutorMessageShown() + &mm_RegisterTutorMessageShown, // pfnRegisterTutorMessageShown() + &mm_GetTimesTutorMessageShown, // pfnGetTimesTutorMessageShown() &mm_ProcessTutorMessageDecayBuffer, // pfnProcessTutorMessageDecayBuffer() &mm_ConstructTutorMessageDecayBuffer, // pfnConstructTutorMessageDecayBuffer() &mm_ResetTutorMessageDecayData, // pfnResetTutorMessageDecayData() - + // Added 2005/08/11 (no SDK update): &mm_QueryClientCvarValue, // pfnQueryClientCvarValue() - + // Added 2005/11/21 (no SDK update): &mm_QueryClientCvarValue2, // pfnQueryClientCvarValue2() // Added 2009/06/17 (no SDK update): - &mm_CheckParm // pfnEngCheckParm() + &mm_EngCheckParm // pfnEngCheckParm() ); diff --git a/metamod/src/engine_api.h b/metamod/src/engine_api.h new file mode 100644 index 0000000..34c35cb --- /dev/null +++ b/metamod/src/engine_api.h @@ -0,0 +1,180 @@ +#pragma once + +#include "comp_dep.h" + +// Plugin's GetEngineFunctions, called by metamod. +typedef int (*GET_ENGINE_FUNCTIONS_FN)(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion); + +// According to SDK engine/eiface.h: +//! enginefuncs_t +//! ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 +#define ENGINE_INTERFACE_VERSION 138 + +// Protect against other projects which use this include file but use the +// normal enginefuncs_t type for their meta_engfuncs. +#ifdef __METAMOD_BUILD__ +#include "meta_eiface.h" // meta_enginefuncs_t +extern meta_enginefuncs_t meta_engfuncs; +#else +extern enginefuncs_t meta_engfuncs; +#endif + +// Typedefs for the above functions: +typedef int (*FN_PRECACHEMODEL)(char* s); +typedef int (*FN_PRECACHESOUND)(char* s); +typedef void (*FN_SETMODEL)(edict_t *e, const char *m); +typedef int (*FN_MODELINDEX)(const char *m); +typedef int (*FN_MODELFRAMES)(int modelIndex); +typedef void (*FN_SETSIZE)(edict_t *e, const float *rgflMin, const float *rgflMax); +typedef void (*FN_CHANGELEVEL)(char *s1, char *s2); +typedef void (*FN_GETSPAWNPARMS)(edict_t *ent); +typedef void (*FN_SAVESPAWNPARMS)(edict_t *ent); +typedef float (*FN_VECTOYAW)(const float *rgflVector); +typedef void (*FN_VECTOANGLES)(const float *rgflVectorIn, float *rgflVectorOut); +typedef void (*FN_MOVETOORIGIN)(edict_t *ent, const float *pflGoal, float dist, int iMoveType); +typedef void (*FN_CHANGEYAW)(edict_t *ent); +typedef void (*FN_CHANGEPITCH)(edict_t *ent); +typedef edict_t *(*FN_FINDENTITYBYSTRING)(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); +typedef int (*FN_GETENTITYILLUM)(edict_t *pEnt); +typedef edict_t *(*FN_FINDENTITYINSPHERE)(edict_t *pEdictStartSearchAfter, const float *org, float rad); +typedef edict_t *(*FN_FINDCLIENTINPVS)(edict_t *pEdict); +typedef edict_t *(*FN_ENTITIESINPVS)(edict_t *pplayer); +typedef void (*FN_MAKEVECTORS)(const float *rgflVector); +typedef void (*FN_ANGLEVECTORS)(const float *rgflVector, float *forward, float *right, float *up); +typedef edict_t *(*FN_CREATEENTITY)(); +typedef void (*FN_REMOVEENTITY)(edict_t *e); +typedef edict_t *(*FN_CREATENAMEDENTITY)(int className); +typedef void (*FN_MAKESTATIC)(edict_t *ent); +typedef int (*FN_ENTISONFLOOR)(edict_t *e); +typedef int (*FN_DROPTOFLOOR)(edict_t *e); +typedef int (*FN_WALKMOVE)(edict_t *ent, float yaw, float dist, int iMode); +typedef void (*FN_SETORIGIN)(edict_t *e, const float *rgflOrigin); +typedef void (*FN_EMITSOUND)(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch); +typedef void (*FN_EMITAMBIENTSOUND)(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); +typedef void (*FN_TRACELINE)(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); +typedef void (*FN_TRACETOSS)(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr); +typedef int (*FN_TRACEMONSTERHULL)(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); +typedef void (*FN_TRACEHULL)(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); +typedef void (*FN_TRACEMODEL)(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); +typedef const char *(*FN_TRACETEXTURE)(edict_t *pTextureEntity, const float *v1, const float *v2); +typedef void (*FN_TRACESPHERE)(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); +typedef void (*FN_GETAIMVECTOR)(edict_t *ent, float speed, float *rgflReturn); +typedef void (*FN_SERVERCOMMAND)(char *str); +typedef void (*FN_SERVEREXECUTE)(); +typedef void (*FN_CLIENTCOMMAND_ENG)(edict_t *pEdict, char *szFmt, ...); +typedef void (*FN_PARTICLEEFFECT)(const float *org, const float *dir, float color, float count); +typedef void (*FN_LIGHTSTYLE)(int style, char *val); +typedef int (*FN_DECALINDEX)(const char *name); +typedef int (*FN_POINTCONTENTS)(const float *rgflVector); +typedef void (*FN_MESSAGEBEGIN)(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); +typedef void (*FN_MESSAGEEND)(); +typedef void (*FN_WRITEBYTE)(int iValue); +typedef void (*FN_WRITECHAR)(int iValue); +typedef void (*FN_WRITESHORT)(int iValue); +typedef void (*FN_WRITELONG)(int iValue); +typedef void (*FN_WRITEANGLE)(float flValue); +typedef void (*FN_WRITECOORD)(float flValue); +typedef void (*FN_WRITESTRING)(const char *sz); +typedef void (*FN_WRITEENTITY)(int iValue); +typedef void (*FN_CVARREGISTER)(cvar_t *pCvar); +typedef float (*FN_CVARGETFLOAT)(const char *szVarName); +typedef const char *(*FN_CVARGETSTRING)(const char *szVarName); +typedef void (*FN_CVARSETFLOAT)(const char *szVarName, float flValue); +typedef void (*FN_CVARSETSTRING)(const char *szVarName, const char *szValue); +typedef void (*FN_ALERTMESSAGE)(ALERT_TYPE atype, char *szFmt, ...); +typedef void (*FN_ENGINEFPRINTF)(void *pfile, char *szFmt, ...); +typedef void *(*FN_PVALLOCENTPRIVATEDATA)(edict_t *pEdict, int32 cb); +typedef void *(*FN_PVENTPRIVATEDATA)(edict_t *pEdict); +typedef void (*FN_FREEENTPRIVATEDATA)(edict_t *pEdict); +typedef const char *(*FN_SZFROMINDEX)(int iString); +typedef int (*FN_ALLOCSTRING)(const char *szValue); +typedef struct entvars_s *(*FN_GETVARSOFENT)(edict_t *pEdict); +typedef edict_t *(*FN_PENTITYOFENTOFFSET)(int iEntOffset); +typedef int (*FN_ENTOFFSETOFPENTITY)(const edict_t *pEdict); +typedef int (*FN_INDEXOFEDICT)(const edict_t *pEdict); +typedef edict_t *(*FN_PENTITYOFENTINDEX)(int iEntIndex); +typedef edict_t *(*FN_FINDENTITYBYVARS)(struct entvars_s *pvars); +typedef void *(*FN_GETMODELPTR)(edict_t *pEdict); +typedef int (*FN_REGUSERMSG)(const char *pszName, int iSize); +typedef void (*FN_ANIMATIONAUTOMOVE)(const edict_t *pEdict, float flTime); +typedef void (*FN_GETBONEPOSITION)(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles); +typedef uint32 (*FN_FUNCTIONFROMNAME)(const char *pName); +typedef const char *(*FN_NAMEFORFUNCTION)(uint32 function); +typedef void (*FN_CLIENTPRINTF)(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg); +typedef void (*FN_SERVERPRINT)(const char *szMsg); +typedef const char *(*FN_CMD_ARGS)(); +typedef const char *(*FN_CMD_ARGV)(int argc); +typedef int (*FN_CMD_ARGC)(); +typedef void (*FN_GETATTACHMENT)(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles); +typedef void (*FN_CRC32_INIT)(CRC32_t *pulCRC); +typedef void (*FN_CRC32_PROCESSBUFFER)(CRC32_t *pulCRC, void *p, int len); +typedef void (*FN_CRC32_PROCESSBYTE)(CRC32_t *pulCRC, unsigned char ch); +typedef CRC32_t (*FN_CRC32_FINAL)(CRC32_t pulCRC); +typedef int32 (*FN_RANDOMLONG)(int32 lLow, int32 lHigh); +typedef float (*FN_RANDOMFLOAT)(float flLow, float flHigh); +typedef void (*FN_SETVIEW)(const edict_t *pClient, const edict_t *pViewent); +typedef float (*FN_TIME)(); +typedef void (*FN_CROSSHAIRANGLE)(const edict_t *pClient, float pitch, float yaw); +typedef byte *(*FN_LOADFILEFORME)(char *filename, int *pLength); +typedef void (*FN_FREEFILE)(void *buffer); +typedef void (*FN_ENDSECTION)(const char *pszSectionName); +typedef int (*FN_COMPAREFILETIME)(char *filename1, char *filename2, int *iCompare); +typedef void (*FN_GETGAMEDIR)(char *szGetGameDir); +typedef void (*FN_CVAR_REGISTERVARIABLE)(cvar_t *variable); +typedef void (*FN_FADECLIENTVOLUME)(const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); +typedef void (*FN_SETCLIENTMAXSPEED)(const edict_t *pEdict, float fNewMaxspeed); +typedef edict_t *(*FN_CREATEFAKECLIENT)(const char *netname); +typedef void (*FN_RUNPLAYERMOVE)(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec); +typedef int (*FN_NUMBEROFENTITIES)(); +typedef char *(*FN_GETINFOKEYBUFFER)(edict_t *e); +typedef char *(*FN_INFOKEYVALUE)(char *infobuffer, char *key); +typedef void (*FN_SETKEYVALUE)(char *infobuffer, char *key, char *value); +typedef void (*FN_SETCLIENTKEYVALUE)(int clientIndex, char *infobuffer, char *key, char *value); +typedef int (*FN_ISMAPVALID)(char *filename); +typedef void (*FN_STATICDECAL)(const float *origin, int decalIndex, int entityIndex, int modelIndex); +typedef int (*FN_PRECACHEGENERIC)(char *s); +typedef int (*FN_GETPLAYERUSERID)(edict_t *e); +typedef void (*FN_BUILDSOUNDMSG)(edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); +typedef int (*FN_ISDEDICATEDSERVER)(); +typedef cvar_t *(*FN_CVARGETPOINTER)(const char *szVarName); +typedef unsigned int (*FN_GETPLAYERWONID)(edict_t *e); +typedef void (*FN_INFO_REMOVEKEY)(char *s, const char *key); +typedef const char *(*FN_GETPHYSICSKEYVALUE)(const edict_t *pClient, const char *key); +typedef void (*FN_SETPHYSICSKEYVALUE)(const edict_t *pClient, const char *key, const char *value); +typedef const char *(*FN_GETPHYSICSINFOSTRING)(const edict_t *pClient); +typedef unsigned short (*FN_PRECACHEEVENT)(int type, const char *psz); +typedef void (*FN_PLAYBACKEVENT)(int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); +typedef unsigned char *(*FN_SETFATPVS)(float *org); +typedef unsigned char *(*FN_SETFATPAS)(float *org); +typedef int (*FN_CHECKVISIBILITY)(const edict_t *entity, unsigned char *pset); +typedef void (*FN_DELTASETFIELD)(struct delta_s *pFields, const char *fieldname); +typedef void (*FN_DELTAUNSETFIELD)(struct delta_s *pFields, const char *fieldname); +typedef void (*FN_DELTAADDENCODER)(char *name, void (*conditionalencode)(struct delta_s *pFields, const unsigned char *from, const unsigned char *to)); +typedef int (*FN_GETCURRENTPLAYER)(); +typedef int (*FN_CANSKIPPLAYER)(const edict_t *player); +typedef int (*FN_DELTAFINDFIELD)(struct delta_s *pFields, const char *fieldname); +typedef void (*FN_DELTASETFIELDBYINDEX)(struct delta_s *pFields, int fieldNumber); +typedef void (*FN_DELTAUNSETFIELDBYINDEX)(struct delta_s *pFields, int fieldNumber); +typedef void (*FN_SETGROUPMASK)(int mask, int op); +typedef int (*FN_CREATEINSTANCEDBASELINE)(int classname, struct entity_state_s *baseline); +typedef void (*FN_CVAR_DIRECTSET)(struct cvar_s *var, char *value); +typedef void (*FN_FORCEUNMODIFIED)(FORCE_TYPE type, float *mins, float *maxs, const char *filename); +typedef void (*FN_GETPLAYERSTATS)(const edict_t *pClient, int *ping, int *packet_loss); +typedef void (*FN_ADDSERVERCOMMAND)(char *cmd_name, void (*function)()); +typedef qboolean (*FN_VOICE_GETCLIENTLISTENING)(int iReceiver, int iSender); +typedef qboolean (*FN_VOICE_SETCLIENTLISTENING)(int iReceiver, int iSender, qboolean bListen); +typedef const char *(*FN_GETPLAYERAUTHID)(edict_t *e); +typedef sequenceEntry_s *(*FN_SEQUENCEGET)(const char* fileName, const char* entryName); +typedef sentenceEntry_s *(*FN_SEQUENCEPICKSENTENCE)(const char* groupName, int pickMethod, int *picked); +typedef int (*FN_GETFILESIZE)(char *filename); +typedef unsigned int (*FN_GETAPPROXWAVEPLAYLEN)(const char *filepath); +typedef int (*FN_ISCAREERMATCH)(); +typedef int (*FN_GETLOCALIZEDSTRINGLENGTH)(const char *label); +typedef void (*FN_REGISTERTUTORMESSAGESHOWN)(int mid); +typedef int (*FN_GETTIMESTUTORMESSAGESHOWN)(int mid); +typedef void (*FN_PROCESSTUTORMESSAGEDECAYBUFFER)(int *buffer, int bufferLength); +typedef void (*FN_CONSTRUCTTUTORMESSAGEDECAYBUFFER)(int *buffer, int bufferLength); +typedef void (*FN_RESETTUTORMESSAGEDECAYDATA)(); +typedef void (*FN_QUERYCLIENTCVARVALUE)(const edict_t *player, const char *cvarName); +typedef void (*FN_QUERYCLIENTCVARVALUE2)(const edict_t *player, const char *cvarName, int requestID); +typedef void (*FN_ENGCHECKPARM)(const char *pchCmdLineToken, char **pchNextVal); diff --git a/metamod/src/engine_t.h b/metamod/src/engine_t.h new file mode 100644 index 0000000..e84f68b --- /dev/null +++ b/metamod/src/engine_t.h @@ -0,0 +1,37 @@ +#pragma once + +#include "eiface.h" // engfuncs_t, globalvars_t +#include "comp_dep.h" + +// Our structure for storing engine references. +struct engine_t { + engine_t(); + engine_t(const engine_t&); + engine_t& operator=(const engine_t&); + + enginefuncs_t *funcs; // engine funcs + globalvars_t *globals; // engine globals + enginefuncs_t *pl_funcs; // "modified" eng funcs we give to plugins +}; + +inline engine_t::engine_t() + : funcs(NULL), globals(NULL), pl_funcs(NULL) +{ +} + + +inline engine_t::engine_t(const engine_t& _rhs) + : funcs(_rhs.funcs), globals(_rhs.globals), pl_funcs(_rhs.pl_funcs) +{ +} + + +inline engine_t& engine_t::operator=(const engine_t& _rhs) +{ + funcs = _rhs.funcs; + globals = _rhs.globals; + pl_funcs = _rhs.pl_funcs; + return *this; +} + +extern engine_t Engine; diff --git a/src/enginecallbacks.h b/metamod/src/enginecallbacks.h similarity index 82% rename from src/enginecallbacks.h rename to metamod/src/enginecallbacks.h index fc1760f..8b8ec23 100644 --- a/src/enginecallbacks.h +++ b/metamod/src/enginecallbacks.h @@ -48,29 +48,29 @@ // when compiling Metamod proper. #ifdef __METAMOD_BUILD__ -# include "meta_eiface.h" // HL_enginefuncs_t +#include "meta_eiface.h" // HL_enginefuncs_t // Use a #define to bend the enginefuncs_t type to our HL_enginefuncs_t // type instead as we now use that for the global object g_engfuncs. -# define enginefuncs_t HL_enginefuncs_t +#define enginefuncs_t HL_enginefuncs_t #endif /* METAMOD_CORE */ #include // ALERT, etc #ifdef __METAMOD_BUILD__ -# undef enginefuncs_t +#undef enginefuncs_t #endif /* METAMOD_CORE */ // Also, create some additional macros for engine callback functions, which // weren't in SDK dlls/enginecallbacks.h but probably should have been. -#define GET_INFOKEYBUFFER (*g_engfuncs.pfnGetInfoKeyBuffer) -#define INFOKEY_VALUE (*g_engfuncs.pfnInfoKeyValue) -#define SET_CLIENT_KEYVALUE (*g_engfuncs.pfnSetClientKeyValue) -#define REG_SVR_COMMAND (*g_engfuncs.pfnAddServerCommand) -#define SERVER_PRINT (*g_engfuncs.pfnServerPrint) -#define SET_SERVER_KEYVALUE (*g_engfuncs.pfnSetKeyValue) -#define QUERY_CLIENT_CVAR_VALUE (*g_engfuncs.pfnQueryClientCvarValue) +#define GET_INFOKEYBUFFER (*g_engfuncs.pfnGetInfoKeyBuffer) +#define INFOKEY_VALUE (*g_engfuncs.pfnInfoKeyValue) +#define SET_CLIENT_KEYVALUE (*g_engfuncs.pfnSetClientKeyValue) +#define REG_SVR_COMMAND (*g_engfuncs.pfnAddServerCommand) +#define SERVER_PRINT (*g_engfuncs.pfnServerPrint) +#define SET_SERVER_KEYVALUE (*g_engfuncs.pfnSetKeyValue) +#define QUERY_CLIENT_CVAR_VALUE (*g_engfuncs.pfnQueryClientCvarValue) #define QUERY_CLIENT_CVAR_VALUE2 (*g_engfuncs.pfnQueryClientCvarValue2) diff --git a/metamod/src/game_support.cpp b/metamod/src/game_support.cpp new file mode 100644 index 0000000..04e4f2f --- /dev/null +++ b/metamod/src/game_support.cpp @@ -0,0 +1,146 @@ +#include "precompiled.h" + +// Adapted from adminmod h_export.cpp: +//! this structure contains a list of supported mods and their dlls names +//! To add support for another mod add an entry here, and add all the +//! exported entities to link_func.cpp +const game_modinfo_t known_games[] = { + // name/gamedir linux_so win_dll desc + // + // Previously enumerated in this sourcefile, the list is now kept in a + // separate file, generated based on game information stored in a + // convenient db. + { "cstrike", "cs.so", "mp.dll", "Counter-Strike" }, + { "czero", "cs.so", "mp.dll", "Counter-Strike:Condition Zero" }, + + // End of list terminator: + { NULL, NULL, NULL, NULL } +}; + +// Find a modinfo corresponding to the given game name. +inline const game_modinfo_t *lookup_game(const char *name) +{ + for (auto& known : known_games) + { + if (known.name && Q_stricmp(known.name, name)) + return &known; + } + + // no match found + return nullptr; +} + +// Installs gamedll from Steam cache +mBOOL install_gamedll(char *from, const char *to) +{ + int length_in; + int length_out; + + if (!from) + return mFALSE; + + if (!to) + to = from; + + byte *cachefile = LOAD_FILE_FOR_ME(from, &length_in); + + // If the file seems to exist in the cache. + if (cachefile) + { + int fd = open(to, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (fd < 0) + { + META_DEBUG(3, ("Installing gamedll from cache: Failed to create file %s: %s", to, strerror(errno)) ); + FREE_FILE(cachefile); + return mFALSE; + } + + length_out=write(fd, cachefile, length_in); + FREE_FILE(cachefile); + close(fd); + + // Writing the file was not successfull + if (length_out != length_in) + { + META_DEBUG(3,("Installing gamedll from chache: Failed to write all %d bytes to file, only %d written: %s", length_in, length_out, strerror(errno))); + + // Let's not leave a mess but clean up nicely. + if (length_out >= 0) + unlink(to); + + return mFALSE; + } + + META_LOG("Installed gamedll %s from cache.", to); + } + else + { + META_DEBUG(3, ("Failed to install gamedll from cache: file %s not found in cache.", from)); + return mFALSE; + } + + return mTRUE; +} + +// Set all the fields in the gamedll struct, - based either on an entry in +// known_games matching the current gamedir, or on one specified manually +// by the server admin. +// +// meta_errno values: +// - ME_NOTFOUND couldn't recognize game +mBOOL setup_gamedll(gamedll_t *gamedll) +{ + const game_modinfo_t *known; + const char *knownfn = nullptr; + + // Check for old-style "metagame.ini" file and complain. + if (valid_gamedir_file(OLD_GAMEDLL_TXT)) + { + META_WARNING("File '%s' is no longer supported; instead, specify override gamedll in %s or with '+localinfo mm_gamedll '", OLD_GAMEDLL_TXT, CONFIG_INI); + } + + // First, look for a known game, based on gamedir. + if ((known = lookup_game(gamedll->name))) + { +#ifdef _WIN32 + knownfn = known->win_dll; +#else + knownfn = known->linux_so; +#endif + + META_DEBUG(4, ("Checking for old version game DLL name '%s'.\n", knownfn)); + safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "dlls/%s", knownfn); + + // Check if the gamedll file exists. If not, try to install it from the cache. + if (!valid_gamedir_file(gamedll->pathname)) + { + safevoid_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), "%s/dlls/%s", gamedll->gamedir, knownfn); + install_gamedll(gamedll->pathname, gamedll->real_pathname); + } + } + else + { + // Neither known-list found a gamedll. + RETURN_ERRNO(mFALSE, ME_NOTFOUND); + } + + + safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "%s/dlls/%s", gamedll->gamedir, knownfn); + + // get filename from pathname + char *cp = Q_strrchr(gamedll->pathname, '/'); + if (cp) + cp++; + else + cp = gamedll->pathname; + + gamedll->file = cp; + + Q_strncpy(gamedll->real_pathname, gamedll->pathname, sizeof(gamedll->real_pathname) - 1); + gamedll->real_pathname[sizeof(gamedll->real_pathname) - 1] = '\0'; + + gamedll->desc = known->desc; + META_LOG("Recognized game '%s'; using dllfile '%s'", gamedll->name, gamedll->file); + + return mTRUE; +} diff --git a/src/game_support.h b/metamod/src/game_support.h similarity index 52% rename from src/game_support.h rename to metamod/src/game_support.h index aed6f3e..04978a5 100644 --- a/src/game_support.h +++ b/metamod/src/game_support.h @@ -1,20 +1,15 @@ -#ifndef GAME_SUPPORT_H -#define GAME_SUPPORT_H +#pragma once #include "types_meta.h" // mBOOL #include "metamod.h" // gamedll_t // Information we have about each game/mod DLL. -typedef struct game_modinfo_s { +struct game_modinfo_t { const char *name; // name (the game dir) const char *linux_so; // filename of linux shared lib const char *win_dll; // filename of win32 dll const char *desc; // our long-name description -} game_modinfo_t; +}; -typedef game_modinfo_t game_modlist_t[]; - -const DLLINTERNAL game_modinfo_t *lookup_game(const char *name); -mBOOL DLLINTERNAL setup_gamedll(gamedll_t *gamedll); - -#endif /* GAME_SUPPORT_H */ +const game_modinfo_t *lookup_game(const char *name); +mBOOL setup_gamedll(gamedll_t *gamedll); diff --git a/src/h_export.cpp b/metamod/src/h_export.cpp similarity index 71% rename from src/h_export.cpp rename to metamod/src/h_export.cpp index 1105943..2f6cbee 100644 --- a/src/h_export.cpp +++ b/metamod/src/h_export.cpp @@ -1,11 +1,4 @@ -#include // always -#include -#include "h_export.h" // me -#include "metamod.h" // engine_t, etc -#include "log_meta.h" // META_DEV, etc -#include "osdep_p.h" // get_module_handle_of_memptr - -// From SDK dlls/h_export.cpp: +#include "precompiled.h" #ifdef _WIN32 //! Required DLL entry point @@ -21,27 +14,23 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRe else if (fdwReason == DLL_PROCESS_DETACH) { /* nothing */ } - return(TRUE); + + return TRUE; } -#elif defined(linux) +#else // Linux routines to correspond to ATTACH and DETACH cases above. These // aren't required by linux, but are included here for completeness, and // just in case we come across a need to do something at dll load or // unload. -void _init(void) { +void _init() { // called before dlopen() returns } -void _fini(void) { + +void _fini() { // called before dlclose() returns } #endif -// Fixed MSVC compiling, by Nikolay "The Storm" Baklicharov. -#if defined(_WIN32) && !defined(__GNUC__) && defined (_MSC_VER) - #pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1") - #pragma comment(linker, "/SECTION:.data,RW") -#endif - //! Holds engine functionality callbacks HL_enginefuncs_t g_engfuncs; globalvars_t *gpGlobals; @@ -52,24 +41,26 @@ engine_t Engine; // This appears to be the _first_ DLL routine called by the engine, so this // is where we hook to load all the other DLLs (game, plugins, etc), which // is actually all done in meta_startup(). -C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, - globalvars_t *pGlobals) +C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, globalvars_t *pGlobals) { #ifdef linux metamod_handle = get_module_handle_of_memptr((void*)&g_engfuncs); #endif + gpGlobals = pGlobals; Engine.funcs = &g_engfuncs; Engine.globals = pGlobals; - Engine.info.initialise(pengfuncsFromEngine); + g_engfuncs.initialise_interface(pengfuncsFromEngine); + // NOTE! Have to call logging function _after_ initialising g_engfuncs, so // that g_engfuncs.pfnAlertMessage() can be resolved properly, heh. :) META_DEV("called: GiveFnptrsToDll"); // Load plugins, load game dll. - if(!metamod_startup()) + if (!metamod_startup()) { metamod_not_loaded = 1; } + return; } diff --git a/src/h_export.h b/metamod/src/h_export.h similarity index 82% rename from src/h_export.h rename to metamod/src/h_export.h index 691f91e..61e9d3b 100644 --- a/src/h_export.h +++ b/metamod/src/h_export.h @@ -1,5 +1,4 @@ -#ifndef H_EXPORT_H -#define H_EXPORT_H +#pragma once #include "osdep.h" // DLLEXPORT, WINAPI, etc @@ -7,5 +6,3 @@ typedef void (WINAPI *GIVE_ENGINE_FUNCTIONS_FN) (enginefuncs_t *pengfuncsFromEngine, globalvars_t *pGlobals); C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pengfuncsFromEngine, globalvars_t *pGlobals); - -#endif /* H_EXPORT_H */ diff --git a/src/linkent.h b/metamod/src/linkent.h similarity index 80% rename from src/linkent.h rename to metamod/src/linkent.h index aa5ef0d..479d732 100644 --- a/src/linkent.h +++ b/metamod/src/linkent.h @@ -1,15 +1,11 @@ -#ifndef LINK_ENT_H -#define LINK_ENT_H +#pragma once -#include // always -#include "osdep.h" // DLLEXPORT, etc -#include "metamod.h" // GameDLL, etc #include "mlist.h" // MPluginList::find_match, etc -#include "mplugin.h" // MPlugin::info, etc -#include "log_meta.h" // META_DEBUG, etc +#include "mplugin.h" // MPlugin::info, etc +#include "log_meta.h" // META_DEBUG, etc //Initializes replacement code -int DLLINTERNAL init_linkent_replacement(DLHANDLE moduleMetamod, DLHANDLE moduleGame); +int init_linkent_replacement(DLHANDLE moduleMetamod, DLHANDLE moduleGame); // Comments from SDK dlls/util.h: //! This is the glue that hooks .MAP entity class names to our CPP classes. @@ -20,7 +16,6 @@ int DLLINTERNAL init_linkent_replacement(DLHANDLE moduleMetamod, DLHANDLE module typedef void (*ENTITY_FN) (entvars_t *); - // For now, we have to explicitly export functions for plugin entities, // just as for gamedll entities. Ideally, this could be generalized in // some manner, so that plugins can declare and use their own entities @@ -42,15 +37,15 @@ typedef void (*ENTITY_FN) (entvars_t *); const char *entStr; \ MPlugin *findp; \ entStr = STRINGIZE(entityName, 0); \ - if(missing) \ + if (missing) \ return; \ - if(!pfnEntity) { \ - if(!(findp=Plugins->find_match(pluginName))) { \ + if (!pfnEntity) { \ + if (!(findp=Plugins->find_match(pluginName))) { \ META_WARNING("Couldn't find loaded plugin '%s' for plugin entity '%s'", pluginName, entStr); \ missing=1; \ return; \ } \ - if(findp->info && findp->info->loadable != PT_STARTUP) { \ + if (findp->info && findp->info->loadable != PT_STARTUP) { \ META_WARNING("Can't link entity '%s' for plugin '%s'; loadable != startup: %s", entStr, pluginName, findp->str_loadable()); \ missing=1; \ return; \ @@ -58,7 +53,7 @@ typedef void (*ENTITY_FN) (entvars_t *); META_DEBUG(9, ("Looking up plugin entity '%s'", entStr)); \ pfnEntity = (ENTITY_FN) DLSYM(findp->handle, entStr); \ } \ - if(!pfnEntity) { \ + if (!pfnEntity) { \ META_WARNING("Couldn't find plugin entity '%s' in plugin DLL '%s'", entStr, findp->file); \ missing=1; \ return; \ @@ -66,5 +61,3 @@ typedef void (*ENTITY_FN) (entvars_t *); META_DEBUG(8, ("Linking plugin entity '%s'", entStr)); \ (*pfnEntity)(pev); \ } - -#endif /* LINK_ENT_H */ diff --git a/src/linkplug.cpp b/metamod/src/linkplug.cpp similarity index 51% rename from src/linkplug.cpp rename to metamod/src/linkplug.cpp index f5dface..78a6f1a 100644 --- a/src/linkplug.cpp +++ b/metamod/src/linkplug.cpp @@ -1,5 +1,4 @@ -#include // always -#include "linkent.h" // LINK_ENTITY_TO_PLUGIN +#include "precompiled.h" // Entity lists for plugins //LINK_ENTITY_TO_PLUGIN(adminmod_timer, "adminmod"); diff --git a/src/log_meta.cpp b/metamod/src/log_meta.cpp similarity index 54% rename from src/log_meta.cpp rename to metamod/src/log_meta.cpp index 148ef68..8514295 100644 --- a/src/log_meta.cpp +++ b/metamod/src/log_meta.cpp @@ -1,138 +1,145 @@ -#include // vsnprintf, etc -#include // va_start, etc -#include // always -#include "enginecallbacks.h" // ALERT, etc -#include "sdk_util.h" // SERVER_PRINT, etc -#include "log_meta.h" // me -#include "osdep.h" // win32 vsnprintf, etc -#include "support_meta.h" // MAX +#include "precompiled.h" -cvar_t meta_debug = {"meta_debug", "0", FCVAR_EXTDLL, 0, NULL}; +cvar_t meta_debug = { "meta_debug", "0", FCVAR_EXTDLL, 0, NULL }; +int meta_debug_value = 0; // meta_debug_value is converted from float(meta_debug.value) to int on every frame -int meta_debug_value = 0; //meta_debug_value is converted from float(meta_debug.value) to int on every frame - -enum MLOG_SERVICE { +enum MLOG_SERVICE +{ mlsCONS = 1, mlsDEV, mlsIWEL, mlsCLIENT }; -static void buffered_ALERT(MLOG_SERVICE service, ALERT_TYPE atype, const char *prefix, const char *fmt, va_list ap); +void buffered_ALERT(MLOG_SERVICE service, ALERT_TYPE atype, const char *prefix, const char *fmt, va_list ap); // Print to console. -void DLLINTERNAL META_CONS(const char *fmt, ...) { +void META_CONS(const char *fmt, ...) +{ va_list ap; char buf[MAX_LOGMSG_LEN]; unsigned int len; + va_start(ap, fmt); safevoid_vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - len=Q_strlen(buf); - if(len < sizeof(buf)-2) { // -1 null, -1 for newline - buf[len+0] = '\n'; - buf[len+1] = 0; + len = Q_strlen(buf); + + // -1 null, -1 for newline + if (len < sizeof(buf) - 2) { + strcat(buf, "\n"); } else - buf[len-1] = '\n'; + buf[len - 1] = '\n'; + SERVER_PRINT(buf); } // Log developer-level messages (obsoleted). -static const char *const prefixDEV = "[META] dev:"; -void DLLINTERNAL META_DEV(const char *fmt, ...) { +void META_DEV(const char *fmt, ...) +{ va_list ap; - int dev; - if(NULL != g_engfuncs.pfnCVarGetFloat) { - dev=(int) CVAR_GET_FLOAT("developer"); - if(dev==0) return; - } + static const char *const prefixDEV = "[META] dev:"; + + //if (!CVAR_GET_FLOAT("developer")) + // return; + va_start(ap, fmt); buffered_ALERT(mlsDEV, at_logged, prefixDEV, fmt, ap); va_end(ap); } // Log infos. -static const char *const prefixINFO = "[META] INFO:"; -void DLLINTERNAL META_INFO(const char *fmt, ...) +void META_INFO(const char *fmt, ...) { va_list ap; + static const char *const prefixINFO = "[META] INFO:"; + va_start(ap, fmt); buffered_ALERT(mlsIWEL, at_logged, prefixINFO, fmt, ap); va_end(ap); } // Log warnings. -static const char *const prefixWARNING = "[META] WARNING:"; -void DLLINTERNAL META_WARNING(const char *fmt, ...) +void META_WARNING(const char *fmt, ...) { va_list ap; + static const char *const prefixWARNING = "[META] WARNING:"; + va_start(ap, fmt); buffered_ALERT(mlsIWEL, at_logged, prefixWARNING, fmt, ap); va_end(ap); } // Log errors. -static const char *const prefixERROR = "[META] ERROR:"; -void DLLINTERNAL META_ERROR(const char *fmt, ...) +void META_ERROR(const char *fmt, ...) { va_list ap; + static const char *const prefixERROR = "[META] ERROR:"; + va_start(ap, fmt); buffered_ALERT(mlsIWEL, at_logged, prefixERROR, fmt, ap); va_end(ap); } // Normal log messages. -static const char *const prefixLOG = "[META]"; -void DLLINTERNAL META_LOG(const char *fmt, ...) +void META_LOG(const char *fmt, ...) { va_list ap; + static const char *const prefixLOG = "[META]"; + va_start(ap, fmt); buffered_ALERT(mlsIWEL, at_logged, prefixLOG, fmt, ap); va_end(ap); } // Print to client. -void DLLINTERNAL META_CLIENT(edict_t *pEntity, const char *fmt, ...) +void META_CLIENT(edict_t *pEntity, const char *fmt, ...) { va_list ap; char buf[MAX_CLIENTMSG_LEN]; unsigned int len; + va_start(ap, fmt); safevoid_vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - len=Q_strlen(buf); - if(len < sizeof(buf)-2) { // -1 null, -1 for newline - buf[len+0] = '\n'; - buf[len+1] = 0; + + len = Q_strlen(buf); + + // -1 null, -1 for newline + if (len < sizeof(buf) - 2) { + strcat(buf, "\n"); } else - buf[len-1] = '\n'; + buf[len - 1] = '\n'; + CLIENT_PRINTF(pEntity, print_console, buf); } #ifndef __BUILD_FAST_METAMOD__ -static int debug_level; +int debug_level; -void DLLINTERNAL META_DEBUG_SET_LEVEL(int level) +void META_DEBUG_SET_LEVEL(int level) { debug_level = level; } -void DLLINTERNAL META_DO_DEBUG(const char *fmt, ...) +void META_DO_DEBUG(const char *fmt, ...) { char meta_debug_str[1024]; va_list ap; + va_start(ap, fmt); safevoid_vsnprintf(meta_debug_str, sizeof(meta_debug_str), fmt, ap); va_end(ap); + ALERT(at_logged, "[META] (debug:%d) %s\n", debug_level, meta_debug_str); } -#endif /*!__BUILD_FAST_METAMOD__*/ +#endif // __BUILD_FAST_METAMOD__ -class BufferedMessage : public class_metamod_new { +class BufferedMessage: public class_metamod_new { public: MLOG_SERVICE service; ALERT_TYPE atype; @@ -141,18 +148,20 @@ public: BufferedMessage *next; }; -static BufferedMessage *messageQueueStart = NULL; -static BufferedMessage *messageQueueEnd = NULL; +BufferedMessage *messageQueueStart = NULL; +BufferedMessage *messageQueueEnd = NULL; -static void buffered_ALERT(MLOG_SERVICE service, ALERT_TYPE atype, const char *prefix, const char *fmt, va_list ap) { +void buffered_ALERT(MLOG_SERVICE service, ALERT_TYPE atype, const char *prefix, const char *fmt, va_list ap) { char buf[MAX_LOGMSG_LEN]; BufferedMessage *msg; - if (NULL != g_engfuncs.pfnAlertMessage) + + if (g_engfuncs.pfnAlertMessage) { vsnprintf(buf, sizeof(buf), fmt, ap); ALERT(atype, "%s %s\n", prefix, buf); return; } + // Engine AlertMessage function not available. Buffer message. msg = new BufferedMessage; if (NULL == msg) @@ -171,19 +180,19 @@ static void buffered_ALERT(MLOG_SERVICE service, ALERT_TYPE atype, const char *p } else { messageQueueEnd->next = msg; messageQueueEnd = msg; - } -} + } +} // Flushes the message queue, printing messages to the respective // service. This function doesn't check anymore if the g_engfuncs // jumptable is set. Don't call it if it isn't set. -void DLLINTERNAL flush_ALERT_buffer(void) +void flush_ALERT_buffer() { BufferedMessage *msg = messageQueueStart; int dev = (int) CVAR_GET_FLOAT("developer"); while (NULL != msg) { - if(msg->service == mlsDEV && dev==0) + if (msg->service == mlsDEV && dev==0) { ; } else { diff --git a/src/log_meta.h b/metamod/src/log_meta.h similarity index 67% rename from src/log_meta.h rename to metamod/src/log_meta.h index 38e92a0..04dc338 100644 --- a/src/log_meta.h +++ b/metamod/src/log_meta.h @@ -1,10 +1,8 @@ -#ifndef LOG_META_H -#define LOG_META_H +#pragma once #include "comp_dep.h" -#include "osdep.h" //unlikely, OPEN_ARGS -// Debug logging. +// Debug logging. // // This is done as a macro, rather than a function. This way, you can add // DEBUG statements all over, without worrying about performance @@ -20,11 +18,11 @@ // cvar, rather than calling CVAR_GET_FLOAT() and thus generating a string // compare for each DEBUG statement. // -// Called as: -// META_DEBUG(3, ("return code: %d", ret)); +// Called as: +// META_DEBUG(3, ("return code: %d", ret)); // // Note the double parens, and the missing parens around "args" in the -// macro itself. Note also the "do..while(0)" loop wrapping the +// macro itself. Note also the "do..while (0)" loop wrapping the // statements, so they become a single statement when expanded, necessary // for times when it might be called as a single-statement result of an // else (or other flow control). @@ -37,15 +35,15 @@ // i686 has fast float compare, but since we want to have i386 binary, we use this. #ifdef __BUILD_FAST_METAMOD__ - #define META_DEBUG(level, args) do { break; } while(0) + #define META_DEBUG(level, args) do { break; } while (0) #else #define META_DEBUG(level, args) \ do { \ - if(unlikely(meta_debug_value >= level)) { \ + if (meta_debug_value >= level) { \ META_DEBUG_SET_LEVEL(level); \ META_DO_DEBUG args; \ } \ - } while(0) + } while (0) #endif // max buffer size for printed messages @@ -54,8 +52,8 @@ // max buffer size for client messages #define MAX_CLIENTMSG_LEN 128 -extern cvar_t meta_debug DLLHIDDEN; -extern int meta_debug_value DLLHIDDEN; +extern cvar_t meta_debug; +extern int meta_debug_value; // META_DEV provides debug logging via the cvar "developer" (when set to 1) // and uses a function call rather than a macro as it's really intended to @@ -63,18 +61,16 @@ extern int meta_debug_value DLLHIDDEN; // server.cfg. // NOTE: META_DEV has now been mostly obsoleted in the code. -void DLLINTERNAL META_CONS(const char *fmt, ...); -void DLLINTERNAL META_DEV(const char *fmt, ...); -void DLLINTERNAL META_INFO(const char *fmt, ...); -void DLLINTERNAL META_WARNING(const char *fmt, ...); -void DLLINTERNAL META_ERROR(const char *fmt, ...); -void DLLINTERNAL META_LOG(const char *fmt, ...); -void DLLINTERNAL META_CLIENT(edict_t *pEntity, const char *fmt, ...); +void META_CONS(const char *fmt, ...); +void META_DEV(const char *fmt, ...); +void META_INFO(const char *fmt, ...); +void META_WARNING(const char *fmt, ...); +void META_ERROR(const char *fmt, ...); +void META_LOG(const char *fmt, ...); +void META_CLIENT(edict_t *pEntity, const char *fmt, ...); #ifndef __BUILD_FAST_METAMOD__ - void DLLINTERNAL META_DEBUG_SET_LEVEL(int level); - void DLLINTERNAL META_DO_DEBUG(const char *fmt, ...); + void META_DEBUG_SET_LEVEL(int level); + void META_DO_DEBUG(const char *fmt, ...); #endif -void DLLINTERNAL flush_ALERT_buffer(void); - -#endif /* LOG_META_H */ +void flush_ALERT_buffer(); diff --git a/src/meta_api.h b/metamod/src/meta_api.h similarity index 96% rename from src/meta_api.h rename to metamod/src/meta_api.h index 5da5556..912477a 100644 --- a/src/meta_api.h +++ b/metamod/src/meta_api.h @@ -48,12 +48,12 @@ typedef struct meta_globals_s { void *override_ret; // readable; return value from overriding/superceding plugin } meta_globals_t; -extern meta_globals_t *gpMetaGlobals DLLHIDDEN; +extern meta_globals_t *gpMetaGlobals; #define SET_META_RESULT(result) gpMetaGlobals->mres=result #define RETURN_META(result) \ - do { gpMetaGlobals->mres=result; return; } while(0) + do { gpMetaGlobals->mres=result; return; } while (0) #define RETURN_META_VALUE(result, value) \ - do { gpMetaGlobals->mres=result; return(value); } while(0) + do { gpMetaGlobals->mres=result; return value; } while (0) #define META_RESULT_STATUS gpMetaGlobals->status #define META_RESULT_PREVIOUS gpMetaGlobals->prev_mres #define META_RESULT_ORIG_RET(type) *(type *)gpMetaGlobals->orig_ret @@ -78,16 +78,16 @@ typedef struct { } gamedll_funcs_t; // Declared in plugin; referenced in macros. -extern gamedll_funcs_t *gpGamedllFuncs DLLHIDDEN; -extern mutil_funcs_t *gpMetaUtilFuncs DLLHIDDEN; +extern gamedll_funcs_t *gpGamedllFuncs; +extern mutil_funcs_t *gpMetaUtilFuncs; // Tell the dll that we'll be loading it as a metamod plugin, in case it // needs to do something special prior to the standard query/attach // procedure. In particular, this will allow for DLL's that can be used as // both standalone DLL's and metamod plugins. (optional; not required in // plugin) -C_DLLEXPORT void Meta_Init(void); -typedef void (*META_INIT_FN) (void); +C_DLLEXPORT void Meta_Init(); +typedef void (*META_INIT_FN)(); // Get info about plugin, compare meta_interface versions, provide meta // utility callback functions. diff --git a/src/meta_eiface.cpp b/metamod/src/meta_eiface.cpp similarity index 56% rename from src/meta_eiface.cpp rename to metamod/src/meta_eiface.cpp index ac75687..ba7fcbe 100644 --- a/src/meta_eiface.cpp +++ b/metamod/src/meta_eiface.cpp @@ -1,24 +1,12 @@ -#include // always -#include // fprintf() -#include // exit() -#include // memset(), memcpy() -#include "meta_eiface.h" // me -#include "dllapi.h" // FN_CVARVALUE, FN_CVARVALUE2 -#include "engine_t.h" // Engine - -// ------------------------------------------------------------------------ -// meta_new_dll_functions_t -// ------------------------------------------------------------------------ - -// static member initialisation -int meta_new_dll_functions_t::sm_version DLLHIDDEN = 0; +#include "precompiled.h" +// meta_new_dll_functions_t meta_new_dll_functions_t::meta_new_dll_functions_t( - void (*_pfnOnFreeEntPrivateData) (edict_t*), - void (*_pfnGameShutdown) (void), - int (*_pfnShouldCollide) (edict_t*, edict_t*), - void (*_pfnCvarValue) (const edict_t*, const char*), - void (*_pfnCvarValue2) (const edict_t*, int, const char*, const char*) + void (*_pfnOnFreeEntPrivateData) (edict_t *), + void (*_pfnGameShutdown) (), + int (*_pfnShouldCollide) (edict_t *, edict_t *), + void (*_pfnCvarValue) (const edict_t *, const char *), + void (*_pfnCvarValue2) (const edict_t *, int, const char *, const char *) ) { pfnOnFreeEntPrivateData = _pfnOnFreeEntPrivateData; @@ -26,96 +14,14 @@ meta_new_dll_functions_t::meta_new_dll_functions_t( pfnShouldCollide = _pfnShouldCollide; pfnCvarValue = _pfnCvarValue; pfnCvarValue2 = _pfnCvarValue2; - Q_memset( dummies, 0, sizeof(pdummyfunc) * c_NumDummies ); } - - -void DLLINTERNAL meta_new_dll_functions_t::copy_to( NEW_DLL_FUNCTIONS *_pFuncs ) +void meta_new_dll_functions_t::copy_to(NEW_DLL_FUNCTIONS *_pFuncs) { - // This is where the magic happens. We check what version of the - // NEW_DLL_FUNCTIONS interface the engine has and calculate the size of - // that interface. Then we only copy the function pointers present in - // that version over to the receiver, so that we do not overwrite his - // memory with functions that he doesn't know of in his copy of the - // struct. - size_t size = get_size(); - if ( 0 == size ) - { - // Ok, this is a real problem and should *not* happen. - // We try to work with NEW_DLL_FUNCTIONS without knowing what - // interface the attached engine uses. This means that the classes - // defined herein are not used in the way they are meant to because - // someone forgot to first create a HL_enginefuncs_t object and - // initialise it with the pointers passed from the engine. - // We treat this as a major developer error and bluntly exit the - // whole process, assuming that this will never happen on a - // production server as it should have been caught by the developer - // during testing. - // - // We use a printf() to complain since we do not know if we have - // already attached to the engine and can use its alerting - // functions. This should be augemnted with a windows version - // popping open a message box. - fprintf( stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" ); - fprintf( stderr, "ERROR: INTERNAL ERROR.\n" ); - fprintf( stderr, " Attempt to use meta_new_dll_functions_t without initialised engine interface version!\n" ); - fprintf( stderr, " %s at %d\n", __FILE__, __LINE__ ); - exit(1); - } - - Q_memcpy( _pFuncs, this, size ); + Q_memcpy(_pFuncs, this, sizeof(NEW_DLL_FUNCTIONS)); } -int DLLINTERNAL meta_new_dll_functions_t::determine_interface_version( void ) -{ - // If the meta_enginefuncs_t::version is 0, i.e. has not yet been - // determined, that is a problem and an error. We should probably throw - // a fit here or something. - // For now we just return 0 and leave it to the caller to complain. - if (meta_enginefuncs_t::version() == 0) return 0; - // The default version is 1. - sm_version = 1; - // With the enginefuncs interface version 156 the function - // pfnCvarValue() was added, which we call version 2. - if (meta_enginefuncs_t::version() >= 156) sm_version = 2; - // With the enginefuncs interface version 157 the function - // pfnCvarValue2() was added, which we call version 3. - if (meta_enginefuncs_t::version() >= 157) sm_version = 3; - return sm_version; -} - - -size_t DLLINTERNAL meta_new_dll_functions_t::get_size( int _version ) -{ - size_t size = sizeof(NEW_DLL_FUNCTIONS); - if ( 0 == _version ) - { - // Use the current engine's interface version - _version = version(); - // Error: meta_enginefuncs_t::version probably not yet set up. - if ( 0 == _version ) return 0; - } - switch( _version ) - { - case 1: - // Version 1 is missing all functions from CvarValue() on. - size -= sizeof(FN_CVARVALUE); - case 2: - // Version 2 is missing all functions from CvarValue2() on. - size -= sizeof(FN_CVARVALUE2); - } - return size; -} - - -// -------------------------------------------------------------- // meta_enginefuncs_t -// -------------------------------------------------------------- - -// static member initialisation -int meta_enginefuncs_t::sm_version = 0; - meta_enginefuncs_t::meta_enginefuncs_t( int (*_pfnPrecacheModel) (const char*), int (*_pfnPrecacheSound) (const char*), @@ -138,7 +44,7 @@ meta_enginefuncs_t::meta_enginefuncs_t( edict_t* (*_pfnEntitiesInPVS) (edict_t*), void (*_pfnMakeVectors) (const float*), void (*_pfnAngleVectors) (const float*, float*, float*, float*), - edict_t* (*_pfnCreateEntity) (void), + edict_t* (*_pfnCreateEntity) (), void (*_pfnRemoveEntity) (edict_t*), edict_t* (*_pfnCreateNamedEntity) (int), void (*_pfnMakeStatic) (edict_t*), @@ -156,15 +62,15 @@ meta_enginefuncs_t::meta_enginefuncs_t( const char* (*_pfnTraceTexture) (edict_t*, const float*, const float*), void (*_pfnTraceSphere) (const float*, const float*, int, float, edict_t*, TraceResult*), void (*_pfnGetAimVector) (edict_t*, float, float*), - void (*_pfnServerCommand) (const char*), - void (*_pfnServerExecute) (void), - void (*_pfnClientCommand) (edict_t*, const char*, ...), + void (*_pfnServerCommand) (char*), + void (*_pfnServerExecute) (), + void (*_pfnClientCommand) (edict_t*, char*, ...), void (*_pfnParticleEffect) (const float*, const float*, float, float), - void (*_pfnLightStyle) (int, const char*), + void (*_pfnLightStyle) (int, char*), int (*_pfnDecalIndex) (const char*), int (*_pfnPointContents) (const float*), void (*_pfnMessageBegin) (int, int, const float*, edict_t*), - void (*_pfnMessageEnd) (void), + void (*_pfnMessageEnd) (), void (*_pfnWriteByte) (int), void (*_pfnWriteChar) (int), void (*_pfnWriteShort) (int), @@ -179,7 +85,7 @@ meta_enginefuncs_t::meta_enginefuncs_t( void (*_pfnCVarSetFloat) (const char*, float), void (*_pfnCVarSetString) (const char*, const char*), void (*_pfnAlertMessage) (ALERT_TYPE, const char*, ...), - void (*_pfnEngineFprintf) (void*, const char*, ...), + void (*_pfnEngineFprintf) (void *, const char*, ...), void* (*_pfnPvAllocEntPrivateData) (edict_t*, int32), void* (*_pfnPvEntPrivateData) (edict_t*), void (*_pfnFreeEntPrivateData) (edict_t*), @@ -194,14 +100,14 @@ meta_enginefuncs_t::meta_enginefuncs_t( void* (*_pfnGetModelPtr) (edict_t*), int (*_pfnRegUserMsg) (const char*, int), void (*_pfnAnimationAutomove) (const edict_t*, float), - void (*_pfnGetBonePosition) (const edict_t*, int, float*, float* ), + void (*_pfnGetBonePosition) (const edict_t*, int, float*, float*), uint32 (*_pfnFunctionFromName) (const char*), const char* (*_pfnNameForFunction) (uint32), void (*_pfnClientPrintf) (edict_t*, PRINT_TYPE, const char*), void (*_pfnServerPrint) (const char*), - const char* (*_pfnCmd_Args) (void), - const char* (*_pfnCmd_Argv) (int argc), - int (*_pfnCmd_Argc) (void), + const char* (*_pfnCmd_Args) (), + const char* (*_pfnCmd_Argv) (int argc), + int (*_pfnCmd_Argc) (), void (*_pfnGetAttachment) (const edict_t*, int, float*, float*), void (*_pfnCRC32_Init) (CRC32_t*), void (*_pfnCRC32_ProcessBuffer) (CRC32_t*, void*, int), @@ -210,31 +116,31 @@ meta_enginefuncs_t::meta_enginefuncs_t( int32 (*_pfnRandomLong) (int32, int32), float (*_pfnRandomFloat) (float, float), void (*_pfnSetView) (const edict_t*, const edict_t*), - float (*_pfnTime) (void), + float (*_pfnTime) (), void (*_pfnCrosshairAngle) (const edict_t*, float, float), - byte* (*_pfnLoadFileForMe) (const char*, int*), + byte* (*_pfnLoadFileForMe) (char*, int*), void (*_pfnFreeFile) (void*), void (*_pfnEndSection) (const char*), int (*_pfnCompareFileTime) (char*, char*, int*), void (*_pfnGetGameDir) (char*), void (*_pfnCvar_RegisterVariable) (cvar_t*), void (*_pfnFadeClientVolume) (const edict_t*, int, int, int, int), - void (*_pfnSetClientMaxspeed) (const edict_t*, float), + void (*_pfnSetClientMaxspeed) (edict_t*, float), edict_t* (*_pfnCreateFakeClient) (const char*), void (*_pfnRunPlayerMove) (edict_t*, const float*, float, float, float, unsigned short, byte, byte), - int (*_pfnNumberOfEntities) (void), + int (*_pfnNumberOfEntities) (), char* (*_pfnGetInfoKeyBuffer) (edict_t*), char* (*_pfnInfoKeyValue) (char*, const char*), void (*_pfnSetKeyValue) (char*, const char*, const char*), void (*_pfnSetClientKeyValue) (int, char*, const char*, const char*), - int (*_pfnIsMapValid) (const char*), + int (*_pfnIsMapValid) (char*), void (*_pfnStaticDecal) (const float*, int, int, int), - int (*_pfnPrecacheGeneric) (const char*), + int (*_pfnPrecacheGeneric) (char*), int (*_pfnGetPlayerUserId) (edict_t*), void (*_pfnBuildSoundMsg) (edict_t*, int, const char*, float, float, int, int, int, int, const float*, edict_t*), - int (*_pfnIsDedicatedServer) (void), + int (*_pfnIsDedicatedServer) (), cvar_t* (*_pfnCVarGetPointer) (const char*), - unsigned int (*_pfnGetPlayerWONId) (edict_t*), + unsigned int (*_pfnGetPlayerWONId) (edict_t*), void (*_pfnInfo_RemoveKey) (char*, const char*), const char* (*_pfnGetPhysicsKeyValue) (const edict_t*, const char*), void (*_pfnSetPhysicsKeyValue) (const edict_t*, const char*, const char*), @@ -243,11 +149,11 @@ meta_enginefuncs_t::meta_enginefuncs_t( void (*_pfnPlaybackEvent) (int, const edict_t*, unsigned short, float, float*, float*, float, float, int, int, int, int), unsigned char* (*_pfnSetFatPVS) (float*), unsigned char* (*_pfnSetFatPAS) (float*), - int (*_pfnCheckVisibility) (const edict_t*, unsigned char*), + int (*_pfnCheckVisibility) (edict_t*, unsigned char*), void (*_pfnDeltaSetField) (struct delta_s*, const char*), void (*_pfnDeltaUnsetField) (struct delta_s*, const char*), - void (*_pfnDeltaAddEncoder) (const char*, void (*)(struct delta_s*, const unsigned char*, const unsigned char*)), - int (*_pfnGetCurrentPlayer) (void), + void (*_pfnDeltaAddEncoder) (char*, void (*)(struct delta_s*, const unsigned char*, const unsigned char*)), + int (*_pfnGetCurrentPlayer) (), int (*_pfnCanSkipPlayer) (const edict_t*), int (*_pfnDeltaFindField) (struct delta_s*, const char*), void (*_pfnDeltaSetFieldByIndex) (struct delta_s*, int), @@ -257,25 +163,25 @@ meta_enginefuncs_t::meta_enginefuncs_t( void (*_pfnCvar_DirectSet) (struct cvar_s*, const char*), void (*_pfnForceUnmodified) (FORCE_TYPE, float*, float*, const char*), void (*_pfnGetPlayerStats) (const edict_t*, int*, int*), - void (*_pfnAddServerCommand) (const char*, void (*) (void)), + void (*_pfnAddServerCommand) (char*, void (*) ()), qboolean (*_pfnVoice_GetClientListening) (int, int), qboolean (*_pfnVoice_SetClientListening) (int, int, qboolean), const char* (*_pfnGetPlayerAuthId) (edict_t*), sequenceEntry_s* (*_pfnSequenceGet) (const char*, const char*), sentenceEntry_s* (*_pfnSequencePickSentence) (const char*, int, int*), - int (*_pfnGetFileSize) (const char*), + int (*_pfnGetFileSize) (char*), unsigned int (*_pfnGetApproxWavePlayLen) (const char*), - int (*_pfnIsCareerMatch) (void), + int (*_pfnIsCareerMatch) (), int (*_pfnGetLocalizedStringLength) (const char*), void (*_pfnRegisterTutorMessageShown) (int), int (*_pfnGetTimesTutorMessageShown) (int), void (*_pfnProcessTutorMessageDecayBuffer) (int*, int), void (*_pfnConstructTutorMessageDecayBuffer)(int*, int), - void (*_pfnResetTutorMessageDecayData) (void), + void (*_pfnResetTutorMessageDecayData) (), void (*_pfnQueryClientCvarValue) (const edict_t*, const char*), void (*_pfnQueryClientCvarValue2) (const edict_t*, const char*, int), - int (*_pfnCheckParm) (const char*, char**) - ) + int (*_pfnEngCheckParm) (const char*, char**) + ) { pfnPrecacheModel = _pfnPrecacheModel; pfnPrecacheSound = _pfnPrecacheSound; @@ -434,221 +340,14 @@ meta_enginefuncs_t::meta_enginefuncs_t( pfnResetTutorMessageDecayData = _pfnResetTutorMessageDecayData; pfnQueryClientCvarValue = _pfnQueryClientCvarValue; pfnQueryClientCvarValue2 = _pfnQueryClientCvarValue2; - pfnCheckParm = _pfnCheckParm; - Q_memset( extra_functions, 0, sizeof(extra_functions)); - Q_memset( dummies, 0, sizeof(pdummyfunc) * c_NumDummies ); + pfnEngCheckParm = _pfnEngCheckParm; } - -// ----------------------------------------------------------------- // HL_enginefuncs -// ----------------------------------------------------------------- - -void HL_enginefuncs_t::initialise_interface( enginefuncs_t *_pFuncs ) +void HL_enginefuncs_t::initialise_interface(enginefuncs_t *_pFuncs) { - set_from( _pFuncs ); + set_from(_pFuncs); // Now the pfnAlertMessage is available and we trust it to be a valid // pointer, so flush the message buffer. flush_ALERT_buffer(); - determine_engine_interface_version(); - fixup_engine_interface(); } - -// The following part (i.e. the end) of the enginefuncs_t struct is -// used to determine the engine interface version since it is the one -// that changed since SDK 212 engines. We call this the "signature" of -// the enginefuncs interface. -// -// Default version is 138. That's what the SDK says. -// -// 144: const char *(*pfnGetPlayerAuthId) ( edict_t *e ); -// -// // PSV: Added for CZ training map -// // const char *(*pfnKeyNameForBinding) ( const char* pBinding ); -// -// sequenceEntry_s* (*pfnSequenceGet) ( const char* fileName, const char* entryName ); -// sentenceEntry_s* (*pfnSequencePickSentence) ( const char* groupName, int pickMethod, int *picked ); -// -// // LH: Give access to filesize via filesystem -// 147: int (*pfnGetFileSize) ( char *filename ); -// -// unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath); -// // MDC: Added for CZ career-mode -// int (*pfnIsCareerMatch) ( void ); -// -// // BGC: return the number of characters of the localized string referenced by using "label" -// int (*pfnGetLocalizedStringLength) (const char *label); -// -// // BGC: added to facilitate persistent storage of tutor message decay values for -// // different career game profiles. Also needs to persist regardless of mp.dll being -// // destroyed and recreated. -// void (*pfnRegisterTutorMessageShown) (int mid); -// int (*pfnGetTimesTutorMessageShown) (int mid); -// void (*pfnProcessTutorMessageDecayBuffer) (int *buffer, int bufferLength); -// void (*pfnConstructTutorMessageDecayBuffer) (int *buffer, int bufferLength); -// 155: void (*pfnResetTutorMessageDecayData) ( void ); - -// 156: void (*pfnQueryClientCvarValue) ( const edict_t *player, const char *cvarName ); -// 157: void (*pfnQueryClientCvarValue2) ( const edict_t *player, const char *cvarName, int requestID ); -// 158: int (*pfnCheckParm) ( const char *pchCmdLineToke, char **pchNextValue ); - -void HL_enginefuncs_t::determine_engine_interface_version( void ) -{ - // We only need to do this once. - if (0 != sm_version) - { - return; - } - // Test every pointer that is part of the signature if it is a valid - // pointer. If it is not, we set it explicitly to NULL. - if ( ! Engine.info.is_valid_code_pointer(pfnGetPlayerAuthId) ) { - pfnGetPlayerAuthId = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnSequenceGet) ) { - pfnSequenceGet = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnSequencePickSentence) ) { - pfnSequencePickSentence = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnGetFileSize) ) { - pfnGetFileSize = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnGetApproxWavePlayLen) ) { - pfnGetApproxWavePlayLen = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnIsCareerMatch) ) { - pfnIsCareerMatch = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnGetLocalizedStringLength) ) { - pfnGetLocalizedStringLength = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnRegisterTutorMessageShown) ) { - pfnRegisterTutorMessageShown = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnGetTimesTutorMessageShown) ) { - pfnGetTimesTutorMessageShown = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnProcessTutorMessageDecayBuffer) ) { - pfnProcessTutorMessageDecayBuffer = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnConstructTutorMessageDecayBuffer) ) { - pfnConstructTutorMessageDecayBuffer = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnResetTutorMessageDecayData) ) { - pfnResetTutorMessageDecayData = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnQueryClientCvarValue) ) { - pfnQueryClientCvarValue = NULL; - } - if ( ! Engine.info.is_valid_code_pointer(pfnQueryClientCvarValue2) ) { - pfnQueryClientCvarValue2 = NULL; - } - // Now begins our heuristic, where we try to determine the engine - // interface version. - // As alluded to above we are currently only interested, and thus - // only detect, versions 144, 147, 156 or 157 (defined by us). - // The minimal default is 138. - sm_version = 138; - // If GetPlayerAuthId() is present, it is at least 144, - // otherwise leave it at the default 138. - // This may give incorrect results for *really* old engine versions, - // i.e. pre 1.1.0.8. We live with that risk. No one uses them anymore. - // Really. - if ( pfnGetPlayerAuthId == NULL ) - { - return; - } - sm_version = 144; - // The two function pointers for pfnSequenceGet() and - // pfnSequencePickSentence() are only valid in a few engine versions - // and are set to NULL in most other version, so they don't get - // checked. - - // If pfnGetFileSize() is present, it is at least 147, - // otherwise leave it at the so far determined value. - if ( pfnGetFileSize == NULL ) - { - return; - } - sm_version = 147; - // Now it gets a bit fuzzy. If all of the functions following GetFileSize() - // but before QueryClientCvarValue() are valid, it is at least 155. - // If even one of them is NULL, then our version can't be higher than 147, - // so use 147. Actually, it could be that there exist engine - // versions where one of them is NULL but the interface is still at - // least 155. If such an engine is found in use, adaptions need to be - // made. - // (Yes, I know this could be done with a little hacky for() loop. We - // don't need to do hacky here.) - int cntInvals = 0; - if ( pfnGetApproxWavePlayLen == NULL ) cntInvals++; - if ( pfnIsCareerMatch == NULL ) cntInvals++; - if ( pfnGetLocalizedStringLength == NULL ) cntInvals++; - if ( pfnRegisterTutorMessageShown == NULL ) cntInvals++; - if ( pfnGetTimesTutorMessageShown == NULL ) cntInvals++; - if ( pfnProcessTutorMessageDecayBuffer == NULL ) cntInvals++; - if ( pfnConstructTutorMessageDecayBuffer == NULL ) cntInvals++; - if ( pfnResetTutorMessageDecayData == NULL ) cntInvals++; - if ( cntInvals > 0 ) - { - return; - } - sm_version = 155; - // All functions up to QueryClientCvarValue() are valid. - // If QueryClientCvarValue() is not valid, leave it at the so far - // determined version. Otherwise the version is at least 156. - if ( pfnQueryClientCvarValue == NULL) - { - return; - } - sm_version = 156; - // All functions up to QueryClientCvarValue2() are valid. - // If QueryClientCvarValue2() is not valid, leave it at the so far - // determined version. Otherwise the version is at least 157. - if ( pfnQueryClientCvarValue2 == NULL) - { - return; - } - sm_version = 157; - // All functions up to EngCheckParm() are valid. - // If EngCheckParm() is not valid, leave it at the so far determined - // version. Otherwise the version is at least 158. - if ( pfnCheckParm == NULL) - { - return; - } - sm_version = 158; -} - -void HL_enginefuncs_t::fixup_engine_interface( void ) -{ - // This function will make sure that all function pointers that aren't - // valid are set to NULL, depending on the engine interface version. - // Sometimes a pointer has a valid value although the function doesn't - // exist in the interface version. - switch ( version() ) - { - case 138: - pfnGetPlayerAuthId = NULL; - case 144: - pfnSequenceGet = NULL; - pfnSequencePickSentence = NULL; - pfnGetFileSize = NULL; - case 147: - pfnGetApproxWavePlayLen = NULL; - pfnIsCareerMatch = NULL; - pfnGetLocalizedStringLength = NULL; - pfnRegisterTutorMessageShown = NULL; - pfnGetTimesTutorMessageShown = NULL; - pfnProcessTutorMessageDecayBuffer = NULL; - pfnConstructTutorMessageDecayBuffer = NULL; - pfnResetTutorMessageDecayData = NULL; - case 155: - pfnQueryClientCvarValue = NULL; - case 156: - pfnQueryClientCvarValue2 = NULL; - case 157: - pfnCheckParm = NULL; - } -} - diff --git a/metamod/src/meta_eiface.h b/metamod/src/meta_eiface.h new file mode 100644 index 0000000..8413263 --- /dev/null +++ b/metamod/src/meta_eiface.h @@ -0,0 +1,302 @@ +#pragma once + +#include // NEW_DLL_FUNCTIONS, enginefuncs_t +#include // memset() + +#include "comp_dep.h" + +// We use our own versions of the engine/dll interface structs. We add a +// few dummy entries to the end and set them to 0. That way we are +// protected from updates to the HL SDK adding new functions which would +// cause a) the game dll copying arbitrary values from us and b) the game +// dll overwriting our memory when using an old Metamod with a new game +// dll. + +// meta_new_dll_functions_t +struct meta_new_dll_functions_t: public NEW_DLL_FUNCTIONS { +public: +// functions: + meta_new_dll_functions_t(); + meta_new_dll_functions_t( + void (*pfnOnFreeEntPrivateData) (edict_t *), + void (*pfnGameShutdown) (), + int (*pfnShouldCollide) (edict_t *, edict_t *), + void (*pfnCvarValue) (const edict_t *, const char *), + void (*pfnCvarValue2) (const edict_t *, int, const char *, const char *) + ); + + meta_new_dll_functions_t(const meta_new_dll_functions_t&); + meta_new_dll_functions_t& operator=(const meta_new_dll_functions_t&); + + // Fill this object with pointers copied from a NEW_DLL_FUNCTIONS struct. + void set_from(NEW_DLL_FUNCTIONS *pFuncs); + + // Copy the pointers from this object to a NEW_DLL_FUNCTIONS struct. + void copy_to(NEW_DLL_FUNCTIONS *pFuncs); +}; + +// Inline functions +inline meta_new_dll_functions_t::meta_new_dll_functions_t() +{ + Q_memset(this, 0, sizeof(meta_new_dll_functions_t)); +} + +inline meta_new_dll_functions_t::meta_new_dll_functions_t(const meta_new_dll_functions_t& _rhs) +{ + Q_memcpy(this, &_rhs, sizeof(NEW_DLL_FUNCTIONS)); +} + +inline meta_new_dll_functions_t& meta_new_dll_functions_t::operator=(const meta_new_dll_functions_t& _rhs) +{ + Q_memcpy(this, &_rhs, sizeof(NEW_DLL_FUNCTIONS)); + return *this; +} + +inline void meta_new_dll_functions_t::set_from(NEW_DLL_FUNCTIONS* _pFuncs) +{ + Q_memcpy(this, _pFuncs, sizeof(NEW_DLL_FUNCTIONS)); +} + +// meta_enginefuncs_t +struct meta_enginefuncs_t: public enginefuncs_t { +public: + // functions: + meta_enginefuncs_t(); + + // Spawn of the devil + meta_enginefuncs_t( + int (*_pfnPrecacheModel)(const char *), + int (*_pfnPrecacheSound)(const char *), + void (*_pfnSetModel)(edict_t *, const char *), + int (*_pfnModelIndex)(const char *), + int (*_pfnModelFrames)(int), + void (*_pfnSetSize)(edict_t *, const float *, const float *), + void (*_pfnChangeLevel)(const char *, const char *), + void (*_pfnGetSpawnParms)(edict_t *), + void (*_pfnSaveSpawnParms)(edict_t *), + float (*_pfnVecToYaw)(const float *), + void (*_pfnVecToAngles)(const float *, float *), + void (*_pfnMoveToOrigin)(edict_t *, const float *, float, int), + void (*_pfnChangeYaw)(edict_t *), + void (*_pfnChangePitch)(edict_t *), + edict_t *(*_pfnFindEntityByString)(edict_t *, const char *, const char *), + int (*_pfnGetEntityIllum)(edict_t *), + edict_t *(*_pfnFindEntityInSphere)(edict_t *, const float *, float), + edict_t *(*_pfnFindClientInPVS)(edict_t *), + edict_t *(*_pfnEntitiesInPVS)(edict_t *), + void (*_pfnMakeVectors)(const float *), + void (*_pfnAngleVectors)(const float *, float *, float *, float *), + edict_t *(*_pfnCreateEntity)(), + void (*_pfnRemoveEntity)(edict_t *), + edict_t *(*_pfnCreateNamedEntity)(int), + + void (*_pfnMakeStatic)(edict_t *), + int (*_pfnEntIsOnFloor)(edict_t *), + int (*_pfnDropToFloor)(edict_t *), + int (*_pfnWalkMove)(edict_t *, float, float, int), + void (*_pfnSetOrigin)(edict_t *, const float *), + void (*_pfnEmitSound)(edict_t *, int, const char *, float, float, int, int), + void (*_pfnEmitAmbientSound)(edict_t *, float *, const char *, float, float, int, int), + void (*_pfnTraceLine)(const float *, const float *, int, edict_t *, TraceResult*), + void (*_pfnTraceToss)(edict_t*, edict_t*, TraceResult *), + int (*_pfnTraceMonsterHull)(edict_t *, const float*, const float*, int, edict_t *, TraceResult *), + void (*_pfnTraceHull)(const float *, const float*, int, int, edict_t*, TraceResult *), + void (*_pfnTraceModel)(const float *, const float*, int, edict_t *, TraceResult *), + const char *(*_pfnTraceTexture)(edict_t *, const float*, const float*), + void (*_pfnTraceSphere)(const float *, const float*, int, float, edict_t*, TraceResult*), + void (*_pfnGetAimVector)(edict_t *, float, float*), + void (*_pfnServerCommand)(char*), + void (*_pfnServerExecute)(), + void (*_pfnClientCommand)(edict_t *, char *, ...), + void (*_pfnParticleEffect)(const float *, const float *, float, float), + void (*_pfnLightStyle)(int, char *), + int (*_pfnDecalIndex)(const char *), + int (*_pfnPointContents)(const float *), + void (*_pfnMessageBegin)(int, int, const float*, edict_t*), + void (*_pfnMessageEnd)(), + + void (*_pfnWriteByte)(int), + void (*_pfnWriteChar)(int), + void (*_pfnWriteShort)(int), + void (*_pfnWriteLong)(int), + void (*_pfnWriteAngle)(float), + void (*_pfnWriteCoord)(float), + void (*_pfnWriteString)(const char *), + void (*_pfnWriteEntity)(int), + void (*_pfnCVarRegister)(cvar_t *), + float (*_pfnCVarGetFloat)(const char *), + const char *(*_pfnCVarGetString)(const char *), + void (*_pfnCVarSetFloat)(const char *, float), + void (*_pfnCVarSetString)(const char *, const char*), + void (*_pfnAlertMessage)(ALERT_TYPE, const char *, ...), + void (*_pfnEngineFprintf)(void *, const char *, ...), + + void *(*_pfnPvAllocEntPrivateData)(edict_t *, int32), + void *(*_pfnPvEntPrivateData)(edict_t *), + void (*_pfnFreeEntPrivateData)(edict_t *), + const char *(*_pfnSzFromIndex)(int), + int (*_pfnAllocString)(const char *), + struct entvars_s*(*_pfnGetVarsOfEnt)(edict_t *), + edict_t *(*_pfnPEntityOfEntOffset)(int), + int (*_pfnEntOffsetOfPEntity)(const edict_t *), + int (*_pfnIndexOfEdict)(const edict_t *), + edict_t *(*_pfnPEntityOfEntIndex)(int), + edict_t *(*_pfnFindEntityByVars)(struct entvars_s *), + void *(*_pfnGetModelPtr)(edict_t *), + int (*_pfnRegUserMsg)(const char *, int), + void (*_pfnAnimationAutomove)(const edict_t *, float), + void (*_pfnGetBonePosition)(const edict_t *, int, float *, float *), + uint32 (*_pfnFunctionFromName)(const char*), + const char *(*_pfnNameForFunction)(uint32), + void (*_pfnClientPrintf)(edict_t *, PRINT_TYPE, const char *), + void (*_pfnServerPrint)(const char *), + const char *(*_pfnCmd_Args)(), + const char *(*_pfnCmd_Argv)(int argc), + int (*_pfnCmd_Argc)(), + void (*_pfnGetAttachment)(const edict_t *, int, float *, float *), + void (*_pfnCRC32_Init)(CRC32_t *), + void (*_pfnCRC32_ProcessBuffer)(CRC32_t *, void *, int), + void (*_pfnCRC32_ProcessByte)(CRC32_t *, unsigned char), + CRC32_t (*_pfnCRC32_Final)(CRC32_t), + int32 (*_pfnRandomLong)(int32, int32), + float (*_pfnRandomFloat)(float, float), + void (*_pfnSetView)(const edict_t *, const edict_t *), + float (*_pfnTime)(), + void (*_pfnCrosshairAngle)(const edict_t *, float, float), + byte *(*_pfnLoadFileForMe)(char *, int *), + void (*_pfnFreeFile)(void *), + + void (*_pfnEndSection)(const char *), + int (*_pfnCompareFileTime)(char *, char *, int *), + void (*_pfnGetGameDir)(char *), + void (*_pfnCvar_RegisterVariable)(cvar_t *), + void (*_pfnFadeClientVolume)(const edict_t *, int, int, int, int), + void (*_pfnSetClientMaxspeed)(edict_t *, float), + edict_t *(*_pfnCreateFakeClient)(const char *), + void (*_pfnRunPlayerMove)(edict_t *, const float *, float, float, float, unsigned short, byte, byte), + int (*_pfnNumberOfEntities)(), + char *(*_pfnGetInfoKeyBuffer)(edict_t *), + char *(*_pfnInfoKeyValue)(char *, const char *), + void (*_pfnSetKeyValue)(char *, const char *, const char *), + void (*_pfnSetClientKeyValue)(int, char *, const char *, const char *), + int (*_pfnIsMapValid)(char *), + void (*_pfnStaticDecal)(const float *, int, int, int), + int (*_pfnPrecacheGeneric)(char *), + int (*_pfnGetPlayerUserId)(edict_t *), + void (*_pfnBuildSoundMsg)(edict_t *, int, const char*, float, float, int, int, int, int, const float *, edict_t *), + int (*_pfnIsDedicatedServer)(), + cvar_t *(*_pfnCVarGetPointer)(const char *), + unsigned int (*_pfnGetPlayerWONId)(edict_t *), + + void (*_pfnInfo_RemoveKey)(char *, const char *), + const char *(*_pfnGetPhysicsKeyValue)(const edict_t *, const char *), + void (*_pfnSetPhysicsKeyValue)(const edict_t *, const char *, const char *), + const char *(*_pfnGetPhysicsInfoString)(const edict_t *), + unsigned short (*_pfnPrecacheEvent)(int, const char *), + void (*_pfnPlaybackEvent)(int, const edict_t *, unsigned short, float, float *, float *, float, float, int, int, int, int), + unsigned char *(*_pfnSetFatPVS)(float *), + unsigned char *(*_pfnSetFatPAS)(float *), + int (*_pfnCheckVisibility)(edict_t *, unsigned char *), + + void (*_pfnDeltaSetField)(struct delta_s *, const char *), + void (*_pfnDeltaUnsetField)(struct delta_s *, const char *), + void (*_pfnDeltaAddEncoder)(char *, void (*)(struct delta_s *, const unsigned char *, const unsigned char *)), + int (*_pfnGetCurrentPlayer)(), + int (*_pfnCanSkipPlayer)(const edict_t *), + int (*_pfnDeltaFindField)(struct delta_s *, const char *), + void (*_pfnDeltaSetFieldByIndex)(struct delta_s *, int), + void (*_pfnDeltaUnsetFieldByIndex)(struct delta_s *, int), + void (*_pfnSetGroupMask)(int, int), + int (*_pfnCreateInstancedBaseline)(int, struct entity_state_s *), + void (*_pfnCvar_DirectSet)(struct cvar_s *, const char *), + + void (*_pfnForceUnmodified)(FORCE_TYPE, float *, float *, const char *), + void (*_pfnGetPlayerStats)(const edict_t *, int *, int *), + void (*_pfnAddServerCommand)(char*, void (*)()), + + qboolean (*_pfnVoice_GetClientListening)(int, int), + qboolean (*_pfnVoice_SetClientListening)(int, int, qboolean), + const char *(*_pfnGetPlayerAuthId)(edict_t *), + sequenceEntry_s *(*_pfnSequenceGet)(const char *, const char *), + sentenceEntry_s *(*_pfnSequencePickSentence)(const char *, int, int *), + int (*_pfnGetFileSize)(char *), + unsigned int (*_pfnGetApproxWavePlayLen)(const char *), + int (*_pfnIsCareerMatch)(), + int (*_pfnGetLocalizedStringLength)(const char *), + void (*_pfnRegisterTutorMessageShown)(int), + int (*_pfnGetTimesTutorMessageShown)(int), + void (*_pfnProcessTutorMessageDecayBuffer)(int*, int), + void (*_pfnConstructTutorMessageDecayBuffer)(int*, int), + void (*_pfnResetTutorMessageDecayData)(), + void (*_pfnQueryClientCvarValue)(const edict_t *, const char *), + void (*_pfnQueryClientCvarValue2)(const edict_t *, const char *, int), + int (*_pfnEngCheckParm)(const char *, char**) + ); + + meta_enginefuncs_t(const meta_enginefuncs_t &); + meta_enginefuncs_t& operator=(const meta_enginefuncs_t &); + + // Fill this object with pointers copied from an enginefuncs_t struct. + void set_from(enginefuncs_t *pFuncs); + + // Copy the pointers from this object to an enginefuncs_t struct. + void copy_to(enginefuncs_t *pFuncs); +}; + +inline meta_enginefuncs_t::meta_enginefuncs_t() +{ + Q_memset(this, 0, sizeof(meta_enginefuncs_t)); +} + +inline meta_enginefuncs_t::meta_enginefuncs_t(const meta_enginefuncs_t &_rhs) +{ + Q_memcpy(this, &_rhs, sizeof(enginefuncs_t)); +} + +inline meta_enginefuncs_t &meta_enginefuncs_t::operator=(const meta_enginefuncs_t &_rhs) +{ + Q_memcpy(this, &_rhs, sizeof(enginefuncs_t)); + return *this; +} + +inline void meta_enginefuncs_t::set_from(enginefuncs_t *_pFuncs) +{ + Q_memcpy(this, _pFuncs, sizeof(enginefuncs_t)); +} + +inline void meta_enginefuncs_t::copy_to(enginefuncs_t *_pFuncs) +{ + Q_memcpy(_pFuncs, this, sizeof(enginefuncs_t)); +} + +// HL_enginefuncs_t +// +// This is a specialisation of the meta_enginefuncs_t struct which is only +// used for the initial copy of the engine functions, i.e. those we get +// passed from the HL engine right at the beginning. +// This specialisation does some extra initialisation when getting set up +// like calculating the engine interface version and fixing up any invalid +// pointers. +// Since there is only one master copy of engine functions this could be +// implemented as a singleton. This is left as an option for later. +// +struct HL_enginefuncs_t: public meta_enginefuncs_t { +public: +// functions: + HL_enginefuncs_t(); + + // Fill this object with pointers copied from an enginefuncs_t struct + // and fixup the interface. + // For this class this happens in the GiveFptrsToDll() function + // with the pointers passed from the HL engine. + void initialise_interface(enginefuncs_t *pFuncs); + +private: +// functions: +public: + // Moving copy_to() and set_from() to the private space. + void set_from(enginefuncs_t *pFuncs) { meta_enginefuncs_t::set_from(pFuncs); }; + void copy_to(enginefuncs_t *pFuncs) { meta_enginefuncs_t::copy_to(pFuncs); }; +}; + +inline HL_enginefuncs_t::HL_enginefuncs_t() : meta_enginefuncs_t() {}; diff --git a/src/metamod.cpp b/metamod/src/metamod.cpp similarity index 67% rename from src/metamod.cpp rename to metamod/src/metamod.cpp index 468fcf5..67ed92e 100644 --- a/src/metamod.cpp +++ b/metamod/src/metamod.cpp @@ -1,33 +1,13 @@ -#include // malloc, etc -#include // errno, etc -#include // always -#include "enginecallbacks.h" // GET_GAME_DIR, etc -#include "metamod.h" // me -#include "h_export.h" // GIVE_ENGINE_FUNCTIONS_FN, etc -#include "mreg.h" // class mCmdList, etc -#include "meta_api.h" // meta_globals_t, etc -#include "mutil.h" // mutil_funcs_t, etc -#include "osdep.h" // DLOPEN, getcwd, is_absolute_path, -#include "reg_support.h" // meta_AddServerCommand, etc -#include "game_support.h" // lookup_game, etc -#include "commands_meta.h" // meta_register_cmdcvar, etc -#include "support_meta.h" // valid_gamedir_file, etc -#include "log_meta.h" // META_LOG, etc -#include "types_meta.h" // mBOOL -#include "info_name.h" // VNAME, etc -#include "vdate.h" // COMPILE_TIME, etc -#include "linkent.h" +#include "precompiled.h" -cvar_t meta_version = {"metamod_version", VVERSION, FCVAR_SERVER, 0, NULL}; +cvar_t meta_version = { "metamod_version", APP_VERSION_STRD, FCVAR_SERVER, 0, NULL }; MConfig static_config; MConfig *Config=&static_config; option_t global_options[] = { { "debuglevel", CF_INT, &Config->debuglevel, "0" }, - { "gamedll", CF_PATH, &Config->gamedll, NULL }, { "plugins_file", CF_PATH, &Config->plugins_file, PLUGINS_INI }, - { "exec_cfg", CF_STR, &Config->exec_cfg, EXEC_CFG }, - { "autodetect", CF_BOOL, &Config->autodetect, "no" }, + { "exec_cfg", CF_STR, &Config->exec_cfg, EXEC_CFG }, { "clientmeta", CF_BOOL, &Config->clientmeta, "yes" }, // list terminator { NULL, CF_NONE, NULL, NULL } @@ -41,66 +21,49 @@ MPluginList *Plugins; MRegCmdList *RegCmds; MRegCvarList *RegCvars; MRegMsgList *RegMsgs; -MPlayerList g_Players; +MPlayerList g_Players; int requestid_counter = 0; DLHANDLE metamod_handle; int metamod_not_loaded = 0; - // Very first metamod function that's run. // Do startup operations... -int DLLINTERNAL metamod_startup(void) { - char *cp, *mmfile=NULL, *cfile=NULL; +int metamod_startup() +{ + char *cp, *mmfile = NULL, *cfile = NULL; META_CONS(" "); - META_CONS(" %s version %s Copyright (c) 2001-%s %s", VNAME, VVERSION, COPYRIGHT_YEAR, VAUTHOR); - META_CONS(" Patch: %s v%d Copyright (c) 2004-%s %s", VPATCH_NAME, VPATCH_IVERSION, VPATCH_COPYRIGHT_YEAR, VPATCH_AUTHOR); - META_CONS(" Modification: v%s from ReHLDS Team (C) 2016", VPATCH_MODIFICATION); - META_CONS(" %s comes with ABSOLUTELY NO WARRANTY; for details type `meta gpl'.", VNAME); + META_CONS(" Metamod version %s Copyright (c) 2001-2016 Will Day (modification ReHLDS Team)", APP_VERSION_STRD); + META_CONS(" Metamod comes with ABSOLUTELY NO WARRANTY; for details type `meta gpl'."); META_CONS(" This is free software, and you are welcome to redistribute it"); META_CONS(" under certain conditions; type `meta gpl' for details."); META_CONS(" "); - META_LOG("%s v%s %s", VNAME, VVERSION, VDATE); - META_LOG("by %s", VAUTHOR); - META_LOG(" %s", VURL); - META_LOG(" Patch: %s v%d", VPATCH_NAME, VPATCH_IVERSION); - META_LOG(" by %s", VPATCH_AUTHOR); - META_LOG(" %s", VPATCH_WEBSITE); - META_LOG("compiled: %s %s (%s)", COMPILE_TIME, COMPILE_TZONE, OPT_TYPE); + META_CONS("Metamod v%s, API (%s)", APP_VERSION_STRD, META_INTERFACE_VERSION); + META_CONS("Metamod build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")"); + META_CONS("Metamod from: " APP_COMMITS_URL APP_COMMIT_ID " " APP_COMMIT_AUTHOR ""); // If running with "+developer", allow an opportunity to break in with // a debugger. - if((int)CVAR_GET_FLOAT("developer") != 0) + if ((int)CVAR_GET_FLOAT("developer") != 0) sleep(1); // Get gamedir, very early on, because it seems we need it all over the // place here at the start. - if(!meta_init_gamedll()) { + if (!meta_init_gamedll()) + { META_ERROR("Failure to init game DLL; exiting..."); - return(0); + return 0; } // Register various console commands and cvars. - // Can I do these here, rather than waiting for GameDLLInit() ? + // Can I do these here, rather than waiting for GameDLLInit() ? // Looks like it works okay.. meta_register_cmdcvar(); - { - //dirty hacks - int vers[4] = {RC_VERS_DWORD}; - char mvers[32]; - - if(vers[2]==0) - safevoid_snprintf(mvers, sizeof(mvers), "%d.%dp%d", vers[0], vers[1], vers[3]); - else - safevoid_snprintf(mvers, sizeof(mvers), "%d.%d.%dp%d", vers[0], vers[1], vers[2], vers[3]); - - CVAR_SET_STRING(meta_version.name, mvers); - } // Set a slight debug level for developer mode, if debug level not // already set. - if((int)CVAR_GET_FLOAT("developer") != 0 && (int)meta_debug.value == 0) { + if ((int)CVAR_GET_FLOAT("developer") != 0 && (int)meta_debug.value == 0) { CVAR_SET_FLOAT("meta_debug", (float)(meta_debug_value = 3)); } @@ -108,42 +71,42 @@ int DLLINTERNAL metamod_startup(void) { Config->init(global_options); // Find config file cfile=CONFIG_INI; - if((cp=LOCALINFO("mm_configfile")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_configfile")) && *cp != '\0') { META_LOG("Configfile specified via localinfo: %s", cp); - if(valid_gamedir_file(cp)) + if (valid_gamedir_file(cp)) cfile=cp; else META_WARNING("Empty/missing config.ini file: %s; falling back to %s", cp, cfile); } // Load config file - if(valid_gamedir_file(cfile)) + if (valid_gamedir_file(cfile)) Config->load(cfile); else META_DEBUG(2, ("No config.ini file found: %s", CONFIG_INI)); // Now, override config options with localinfo commandline options. - if((cp=LOCALINFO("mm_debug")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_debug")) && *cp != '\0') { META_LOG("Debuglevel specified via localinfo: %s", cp); Config->set("debuglevel", cp); } - if((cp=LOCALINFO("mm_gamedll")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_gamedll")) && *cp != '\0') { META_LOG("Gamedll specified via localinfo: %s", cp); Config->set("gamedll", cp); } - if((cp=LOCALINFO("mm_pluginsfile")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_pluginsfile")) && *cp != '\0') { META_LOG("Pluginsfile specified via localinfo: %s", cp); Config->set("plugins_file", cp); } - if((cp=LOCALINFO("mm_execcfg")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_execcfg")) && *cp != '\0') { META_LOG("Execcfg specified via localinfo: %s", cp); Config->set("exec_cfg", cp); } - if((cp=LOCALINFO("mm_autodetect")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_autodetect")) && *cp != '\0') { META_LOG("Autodetect specified via localinfo: %s", cp); Config->set("autodetect", cp); } - if((cp=LOCALINFO("mm_clientmeta")) && *cp != '\0') { + if ((cp=LOCALINFO("mm_clientmeta")) && *cp != '\0') { META_LOG("Clientmeta specified via localinfo: %s", cp); Config->set("clientmeta", cp); } @@ -151,7 +114,7 @@ int DLLINTERNAL metamod_startup(void) { // Check for an initial debug level, since cfg files don't get exec'd // until later. - if(Config->debuglevel != 0) { + if (Config->debuglevel != 0) { CVAR_SET_FLOAT("meta_debug", (float)(meta_debug_value = Config->debuglevel)); } @@ -161,7 +124,7 @@ int DLLINTERNAL metamod_startup(void) { // Prepare for registered user messages from gamedll. RegMsgs = new MRegMsgList(); - + // Copy, and store pointer in Engine struct. Yes, we could just store // the actual engine_t struct in Engine, but then it wouldn't be a // pointer to match the other g_engfuncs. @@ -172,13 +135,13 @@ int DLLINTERNAL metamod_startup(void) { Engine.pl_funcs->pfnCVarRegister = meta_CVarRegister; Engine.pl_funcs->pfnCvar_RegisterVariable = meta_CVarRegister; Engine.pl_funcs->pfnRegUserMsg = meta_RegUserMsg; - if(IS_VALID_PTR((void*)Engine.pl_funcs->pfnQueryClientCvarValue)) + if (IS_VALID_PTR((void*)Engine.pl_funcs->pfnQueryClientCvarValue)) Engine.pl_funcs->pfnQueryClientCvarValue = meta_QueryClientCvarValue; else Engine.pl_funcs->pfnQueryClientCvarValue = NULL; - if(!IS_VALID_PTR((void*)Engine.pl_funcs->pfnQueryClientCvarValue2)) + if (!IS_VALID_PTR((void*)Engine.pl_funcs->pfnQueryClientCvarValue2)) Engine.pl_funcs->pfnQueryClientCvarValue2 = NULL; - + // Before, we loaded plugins before loading the game DLL, so that if no // plugins caught engine functions, we could pass engine funcs straight // to game dll, rather than acting as intermediary. (Should perform @@ -196,28 +159,28 @@ int DLLINTERNAL metamod_startup(void) { // does) then it needs to be non-null so META_ENGINE_HANDLE won't crash. // // However, having replaced valid_file with valid_gamedir_file, we need - // to at least initialize the gameDLL to include the gamedir, before + // to at least initialize the gameDLL to include the gamedir, before // looking for plugins.ini. // // In fact, we need gamedir even earlier, so moved up above. // Fall back to old plugins filename, if configured one isn't found. mmfile=PLUGINS_INI; - if(!valid_gamedir_file(PLUGINS_INI) && valid_gamedir_file(OLD_PLUGINS_INI)) + if (!valid_gamedir_file(PLUGINS_INI) && valid_gamedir_file(OLD_PLUGINS_INI)) mmfile=OLD_PLUGINS_INI; - if(valid_gamedir_file(Config->plugins_file)) + if (valid_gamedir_file(Config->plugins_file)) mmfile=Config->plugins_file; else - META_WARNING("Plugins file is empty/missing: %s; falling back to %s", + META_WARNING("Plugins file is empty/missing: %s; falling back to %s", Config->plugins_file, mmfile); Plugins = new MPluginList(mmfile); - if(!meta_load_gamedll()) { + if (!meta_load_gamedll()) { META_ERROR("Failure to load game DLL; exiting..."); - return(0); + return 0; } - if(!Plugins->load()) { + if (!Plugins->load()) { META_WARNING("Failure to load plugins..."); // Exit on failure here? Dunno... } @@ -228,15 +191,15 @@ int DLLINTERNAL metamod_startup(void) { // Only attempt load if the file appears to exist and be non-empty, to // avoid confusing users with "couldn't exec exec.cfg" console // messages. - if(valid_gamedir_file(Config->exec_cfg)) + if (valid_gamedir_file(Config->exec_cfg)) mmfile=Config->exec_cfg; - else if(valid_gamedir_file(OLD_EXEC_CFG)) + else if (valid_gamedir_file(OLD_EXEC_CFG)) mmfile=OLD_EXEC_CFG; else mmfile=NULL; - - if(mmfile) { - if(mmfile[0]=='/') + + if (mmfile) { + if (mmfile[0]=='/') META_WARNING("Cannot exec absolute pathnames: %s", mmfile); else { char cmd[NAME_MAX]; @@ -245,14 +208,14 @@ int DLLINTERNAL metamod_startup(void) { SERVER_COMMAND(cmd); } } - - return(1); + + return 1; } // Set initial GameDLL fields (name, gamedir). // meta_errno values: // - ME_NULLRESULT getcwd failed -mBOOL DLLINTERNAL meta_init_gamedll(void) { +mBOOL meta_init_gamedll() { char gamedir[PATH_MAX]; char *cp; @@ -271,30 +234,38 @@ mBOOL DLLINTERNAL meta_init_gamedll(void) { // Note: the code has always assumed the server op wouldn't do: // hlds -game other/firearms // - if(is_absolute_path(gamedir)) { + if (is_absolute_path(gamedir)) + { // Old style; GET_GAME_DIR returned full pathname. Copy this into // our gamedir, and truncate to get the game name. // (note check for both linux and win32 full pathname.) - STRNCPY(GameDLL.gamedir, gamedir, sizeof(GameDLL.gamedir)); - cp=Q_strrchr(gamedir, '/') + 1; - STRNCPY(GameDLL.name, cp, sizeof(GameDLL.name)); + Q_strncpy(GameDLL.gamedir, gamedir, sizeof(GameDLL.gamedir) - 1); + GameDLL.gamedir[sizeof(GameDLL.gamedir) - 1] = '\0'; + + cp = Q_strrchr(gamedir, '/') + 1; + + Q_strncpy(GameDLL.name, cp, sizeof(GameDLL.name) - 1); + GameDLL.name[sizeof(GameDLL.name) - 1] = '\0'; } - else { + else + { // New style; GET_GAME_DIR returned game name. Copy this into our // game name, and prepend the current working directory. char buf[PATH_MAX]; - if(!getcwd(buf, sizeof(buf))) { + if (!getcwd(buf, sizeof(buf))) + { META_WARNING("dll: Couldn't get cwd; %s", strerror(errno)); RETURN_ERRNO(mFALSE, ME_NULLRESULT); } - safevoid_snprintf(GameDLL.gamedir, sizeof(GameDLL.gamedir), - "%s/%s", buf, gamedir); - STRNCPY(GameDLL.name, gamedir, sizeof(GameDLL.name)); + safevoid_snprintf(GameDLL.gamedir, sizeof(GameDLL.gamedir), "%s/%s", buf, gamedir); + + Q_strncpy(GameDLL.name, gamedir, sizeof(GameDLL.name) - 1); + GameDLL.name[sizeof(GameDLL.name) - 1] = '\0'; } META_DEBUG(3, ("Game: %s", GameDLL.name)); - return(mTRUE); + return mTRUE; } // Load game DLL. @@ -302,7 +273,7 @@ mBOOL DLLINTERNAL meta_init_gamedll(void) { // - ME_DLOPEN couldn't dlopen game dll file // - ME_DLMISSING couldn't find required routine in game dll // (GiveFnptrsToDll, GetEntityAPI, GetEntityAPI2) -mBOOL DLLINTERNAL meta_load_gamedll(void) { +mBOOL meta_load_gamedll() { int iface_vers; int found=0; @@ -311,15 +282,15 @@ mBOOL DLLINTERNAL meta_load_gamedll(void) { GETENTITYAPI2_FN pfn_getapi2; GETENTITYAPI_FN pfn_getapi; - if(!setup_gamedll(&GameDLL)) { + if (!setup_gamedll(&GameDLL)) { META_WARNING("dll: Unrecognized game: %s", GameDLL.name); // meta_errno should be already set in lookup_game() - return(mFALSE); + return mFALSE; } // open the game DLL - if(!(GameDLL.handle=DLOPEN(GameDLL.pathname))) { - META_WARNING("dll: Couldn't load game DLL %s: %s", GameDLL.pathname, + if (!(GameDLL.handle=DLOPEN(GameDLL.pathname))) { + META_WARNING("dll: Couldn't load game DLL %s: %s", GameDLL.pathname, DLERROR()); RETURN_ERRNO(mFALSE, ME_DLOPEN); } @@ -328,34 +299,34 @@ mBOOL DLLINTERNAL meta_load_gamedll(void) { // wanted to catch one of the functions, but now that plugins are // dynamically loadable at any time, we have to always pass our table, // so that any plugin loaded later can catch what they need to. - if((pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(GameDLL.handle, "GiveFnptrsToDll"))) + if ((pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(GameDLL.handle, "GiveFnptrsToDll"))) { pfn_give_engfuncs(&meta_engfuncs, gpGlobals); - META_DEBUG(3, ("dll: Game '%s': Called GiveFnptrsToDll", + META_DEBUG(3, ("dll: Game '%s': Called GiveFnptrsToDll", GameDLL.name)); - - //activate linkent-replacement after give_engfuncs so that if game dll is - //plugin too and uses same method we get combined export table of plugin + + //activate linkent-replacement after give_engfuncs so that if game dll is + //plugin too and uses same method we get combined export table of plugin //and game dll - if(!init_linkent_replacement(metamod_handle, GameDLL.handle)) { + if (!init_linkent_replacement(metamod_handle, GameDLL.handle)) { META_WARNING("dll: Couldn't load linkent replacement for game DLL"); RETURN_ERRNO(mFALSE, ME_DLERROR); } } else { - META_WARNING("dll: Couldn't find GiveFnptrsToDll() in game DLL '%s': %s", + META_WARNING("dll: Couldn't find GiveFnptrsToDll() in game DLL '%s': %s", GameDLL.name, DLERROR()); RETURN_ERRNO(mFALSE, ME_DLMISSING); } // Yes...another macro. #define GET_FUNC_TABLE_FROM_GAME(gamedll, pfnGetFuncs, STR_GetFuncs, struct_field, API_TYPE, TABLE_TYPE, vers_pass, vers_int, vers_want, gotit) \ - if((pfnGetFuncs = (API_TYPE) DLSYM(gamedll.handle, STR_GetFuncs))) { \ + if ((pfnGetFuncs = (API_TYPE) DLSYM(gamedll.handle, STR_GetFuncs))) { \ gamedll.funcs.struct_field = (TABLE_TYPE*) calloc(1, sizeof(TABLE_TYPE)); \ - if(!gamedll.funcs.struct_field) {\ + if (!gamedll.funcs.struct_field) {\ META_WARNING("malloc failed for gamedll struct_field: %s", STR_GetFuncs); \ } \ - else if(pfnGetFuncs(gamedll.funcs.struct_field, vers_pass)) { \ + else if (pfnGetFuncs(gamedll.funcs.struct_field, vers_pass)) { \ META_DEBUG(3, ("dll: Game '%s': Found %s", gamedll.name, STR_GetFuncs)); \ gotit=1; \ } \ @@ -363,13 +334,13 @@ mBOOL DLLINTERNAL meta_load_gamedll(void) { META_WARNING("dll: Failure calling %s in game '%s'", STR_GetFuncs, gamedll.name); \ free(gamedll.funcs.struct_field); \ gamedll.funcs.struct_field=NULL; \ - if(vers_int != vers_want) { \ + if (vers_int != vers_want) { \ META_WARNING("dll: Interface version didn't match; we wanted %d, they had %d", vers_want, vers_int); \ /* reproduce error from engine */ \ META_CONS("=================="); \ META_CONS("Game DLL version mismatch"); \ META_CONS("DLL version is %d, engine version is %d", vers_int, vers_want); \ - if(vers_int > vers_want) \ + if (vers_int > vers_want) \ META_CONS("Engine appears to be outdated, check for updates"); \ else \ META_CONS("The game DLL for %s appears to be outdated, check for updates", GameDLL.name); \ @@ -383,34 +354,30 @@ mBOOL DLLINTERNAL meta_load_gamedll(void) { gamedll.funcs.struct_field=NULL; \ } - // Look for API-NEW interface in Game dll. We do this before API2/API, because + // Look for API-NEW interface in Game dll. We do this before API2/API, because // that's what the engine appears to do.. iface_vers=NEW_DLL_FUNCTIONS_VERSION; - GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapinew, "GetNewDLLFunctions", newapi_table, - GETNEWDLLFUNCTIONS_FN, meta_new_dll_functions_t, - &iface_vers, iface_vers, NEW_DLL_FUNCTIONS_VERSION, found); + GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapinew, "GetNewDLLFunctions", newapi_table, GETNEWDLLFUNCTIONS_FN, meta_new_dll_functions_t, &iface_vers, iface_vers, NEW_DLL_FUNCTIONS_VERSION, found); // Look for API2 interface in plugin; preferred over API-1. found=0; iface_vers=INTERFACE_VERSION; - GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapi2, "GetEntityAPI2", dllapi_table, - GETENTITYAPI2_FN, DLL_FUNCTIONS, - &iface_vers, iface_vers, INTERFACE_VERSION, found); + GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapi2, "GetEntityAPI2", dllapi_table, GETENTITYAPI2_FN, DLL_FUNCTIONS, &iface_vers, iface_vers, INTERFACE_VERSION, found); // Look for API-1 in plugin, if API2 interface wasn't found. - if(!found) { - found=0; - GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapi, "GetEntityAPI", dllapi_table, - GETENTITYAPI_FN, DLL_FUNCTIONS, - INTERFACE_VERSION, INTERFACE_VERSION, INTERFACE_VERSION, found); + if (!found) + { + found = 0; + GET_FUNC_TABLE_FROM_GAME(GameDLL, pfn_getapi, "GetEntityAPI", dllapi_table, GETENTITYAPI_FN, DLL_FUNCTIONS, INTERFACE_VERSION, INTERFACE_VERSION, INTERFACE_VERSION, found); } // If didn't find either, return failure. - if(!found) { + if (!found) + { META_WARNING("dll: Couldn't find either GetEntityAPI nor GetEntityAPI2 in game DLL '%s'", GameDLL.name); RETURN_ERRNO(mFALSE, ME_DLMISSING); } META_LOG("Game DLL for '%s' loaded successfully", GameDLL.desc); - return(mTRUE); + return mTRUE; } diff --git a/src/metamod.h b/metamod/src/metamod.h similarity index 82% rename from src/metamod.h rename to metamod/src/metamod.h index 59df820..add396c 100644 --- a/src/metamod.h +++ b/metamod/src/metamod.h @@ -27,10 +27,10 @@ #define CONFIG_INI "addons/metamod/config.ini" // metamod module handle -extern DLHANDLE metamod_handle DLLHIDDEN; +extern DLHANDLE metamod_handle; // cvar to contain version -extern cvar_t meta_version DLLHIDDEN; +extern cvar_t meta_version; // Info about the game dll/mod. typedef struct gamedll_s { @@ -43,52 +43,52 @@ typedef struct gamedll_s { DLHANDLE handle; gamedll_funcs_t funcs; // dllapi_table, newapi_table } gamedll_t; -extern gamedll_t GameDLL DLLHIDDEN; +extern gamedll_t GameDLL; // SDK variables for storing engine funcs and globals. -extern HL_enginefuncs_t g_engfuncs DLLHIDDEN; -extern globalvars_t *gpGlobals DLLHIDDEN; +extern HL_enginefuncs_t g_engfuncs; +extern globalvars_t *gpGlobals; // Our modified version of the engine funcs, to give to plugins. -extern meta_enginefuncs_t g_plugin_engfuncs DLLHIDDEN; +extern meta_enginefuncs_t g_plugin_engfuncs; // Config structure. -extern MConfig *Config DLLHIDDEN; +extern MConfig *Config; // List of plugins loaded/opened/running. -extern MPluginList *Plugins DLLHIDDEN; +extern MPluginList *Plugins; // List of command functions registered by plugins. -extern MRegCmdList *RegCmds DLLHIDDEN; +extern MRegCmdList *RegCmds; // List of cvar structures registered by plugins. -extern MRegCvarList *RegCvars DLLHIDDEN; +extern MRegCvarList *RegCvars; // List of user messages registered by gamedll. -extern MRegMsgList *RegMsgs DLLHIDDEN; +extern MRegMsgList *RegMsgs; // Data provided to plugins. // Separate copies to prevent plugins from modifying "readable" parts. // See meta_api.h for meta_globals_t structure. -extern meta_globals_t PublicMetaGlobals DLLHIDDEN; -extern meta_globals_t PrivateMetaGlobals DLLHIDDEN; +extern meta_globals_t PublicMetaGlobals; +extern meta_globals_t PrivateMetaGlobals; // hook function tables -extern DLL_FUNCTIONS *g_pHookedDllFunctions DLLHIDDEN; -extern NEW_DLL_FUNCTIONS *g_pHookedNewDllFunctions DLLHIDDEN; +extern DLL_FUNCTIONS *g_pHookedDllFunctions; +extern NEW_DLL_FUNCTIONS *g_pHookedNewDllFunctions; -extern int metamod_not_loaded DLLHIDDEN; +extern int metamod_not_loaded; // Holds cached player info, right now only things for querying cvars // Max players is always 32, small enough that we can use a static array -extern MPlayerList g_Players DLLHIDDEN; +extern MPlayerList g_Players; -extern int requestid_counter DLLHIDDEN; +extern int requestid_counter; -int DLLINTERNAL metamod_startup(void); +int metamod_startup(); -mBOOL DLLINTERNAL meta_init_gamedll(void); -mBOOL DLLINTERNAL meta_load_gamedll(void); +mBOOL meta_init_gamedll(); +mBOOL meta_load_gamedll(); // ===== lotsa macros... ====================================================== @@ -147,7 +147,7 @@ mBOOL DLLINTERNAL meta_load_gamedll(void); // ===== macros for void-returning functions ================================== -// return (void) +// return () #define RETURN_API_void() \ return; @@ -155,7 +155,7 @@ mBOOL DLLINTERNAL meta_load_gamedll(void); // return a value #define RETURN_API(ret_t) \ - {return(GET_RET_CLASS(ret_val, ret_t));} + { return GET_RET_CLASS(ret_val, ret_t); } // ===== end macros =========================================================== @@ -165,15 +165,15 @@ mBOOL DLLINTERNAL meta_load_gamedll(void); // Api-hook performance monitoring // ============================================================================ -extern long double total_tsc DLLHIDDEN; -extern unsigned long long count_tsc DLLHIDDEN; -extern unsigned long long active_tsc DLLHIDDEN; -extern unsigned long long min_tsc DLLHIDDEN; +extern long double total_tsc; +extern unsigned long long count_tsc; +extern unsigned long long active_tsc; +extern unsigned long long min_tsc; -inline unsigned long long DLLINTERNAL GET_TSC(void) { +inline unsigned long long GET_TSC() { union { struct { unsigned int eax, edx; } split; unsigned long long full; } tsc; #ifdef __GNUC__ - __asm__ __volatile__("rdtsc":"=a"(tsc.split.eax), "=d"(tsc.split.edx)); + __asm__ __volatile__("rdtsc":"=a"(tsc.split.eax), "=d"(tsc.split.edx)); #else __asm { @@ -182,7 +182,7 @@ inline unsigned long long DLLINTERNAL GET_TSC(void) { mov tsc.split.edx, edx } #endif - return(tsc.full); + return tsc.full; } #define API_START_TSC_TRACKING() \ @@ -198,7 +198,7 @@ inline unsigned long long DLLINTERNAL GET_TSC(void) { unsigned long long run_tsc = GET_TSC() - active_tsc; \ total_tsc += run_tsc; \ count_tsc++; \ - if(min_tsc == 0 || run_tsc < min_tsc) \ + if (min_tsc == 0 || run_tsc < min_tsc) \ min_tsc = run_tsc; \ } diff --git a/src/mhook.cpp b/metamod/src/mhook.cpp similarity index 100% rename from src/mhook.cpp rename to metamod/src/mhook.cpp diff --git a/src/mlist.cpp b/metamod/src/mlist.cpp similarity index 53% rename from src/mlist.cpp rename to metamod/src/mlist.cpp index 2f56877..ab3ebf4 100644 --- a/src/mlist.cpp +++ b/metamod/src/mlist.cpp @@ -1,44 +1,36 @@ -#include // errno, etc -#include // always -#include "mlist.h" // me -#include "mplugin.h" // class MPlugin -#include "plinfo.h" // plid_t, etc -#include "commands_meta.h" // cmd_meta_pluginlist, etc -#include "metamod.h" // GameDLL, etc -#include "types_meta.h" // mBOOL -#include "log_meta.h" // META_LOG, etc -#include "osdep.h" // win32 snprintf, normalize_pathname, -#include "osdep_p.h" +#include "precompiled.h" // Constructor -MPluginList::MPluginList(const char *ifile) +MPluginList::MPluginList(const char *ifile) : size(MAX_PLUGINS), endlist(0) { - int i; // store filename of ini file - STRNCPY(inifile, ifile, sizeof(inifile)); + Q_strncpy(inifile, ifile, sizeof(inifile) - 1); + inifile[sizeof(inifile) - 1] = '\0'; + // initialize array - for(i=0; i < size; i++) { + for (int i = 0; i < size; i++) + { //reset to empty - plist[i].index=i+1; + plist[i].index = i + 1; reset_plugin(&plist[i]); } - endlist=0; + + endlist = 0; } // Resets plugin to empty -void DLLINTERNAL MPluginList::reset_plugin(MPlugin *pl_find) { - int i; - +void MPluginList::reset_plugin(MPlugin *pl_find) +{ //calculate index - i = pl_find - &plist[0]; - + int i = pl_find - &plist[0]; + //free any pointers first pl_find->free_api_pointers(); - + //set zero Q_memset(pl_find, 0, sizeof(*pl_find)); - + pl_find->index=i+1; // 1-based } @@ -46,99 +38,110 @@ void DLLINTERNAL MPluginList::reset_plugin(MPlugin *pl_find) { // meta_errno values: // - ME_ARGUMENT invalid pindex // - ME_NOTFOUND couldn't find a matching plugin -MPlugin * DLLINTERNAL MPluginList::find(int pindex) { - MPlugin *pfound; - if(pindex <= 0) +MPlugin *MPluginList::find(int pindex) +{ + if (pindex <= 0) RETURN_ERRNO(NULL, ME_ARGUMENT); - pfound=&plist[pindex-1]; - if(pfound->status < PL_VALID) + + MPlugin *pfound = &plist[pindex - 1]; + if (pfound->status < PL_VALID) RETURN_ERRNO(NULL, ME_NOTFOUND); else - return(pfound); + return pfound; } // Find a plugin based on the plugin handle. // meta_errno values: // - ME_ARGUMENT invalid pindex // - ME_NOTFOUND couldn't find a matching plugin -MPlugin * DLLINTERNAL MPluginList::find(DLHANDLE handle) { - int i; - - if(!handle) +MPlugin *MPluginList::find(DLHANDLE handle) +{ + if (!handle) RETURN_ERRNO(NULL, ME_ARGUMENT); - for(i=0; i < endlist; i++) { - if(plist[i].status < PL_VALID) + + for (int i = 0; i < endlist; i++) + { + if (plist[i].status < PL_VALID) continue; - if(plist[i].handle == handle) - return(&plist[i]); + + if (plist[i].handle == handle) + return &plist[i]; } + RETURN_ERRNO(NULL, ME_NOTFOUND); } // Clear source_plugin_index on all matching plugins -void DLLINTERNAL MPluginList::clear_source_plugin_index(int source_index) { - int i; - - if(source_index <= 0) +void MPluginList::clear_source_plugin_index(int source_index) +{ + if (source_index <= 0) return; - - for(i=0; i < endlist; i++) { - if(plist[i].status < PL_VALID) + + for (int i = 0; i < endlist; i++) + { + if (plist[i].status < PL_VALID) continue; - if(plist[i].source_plugin_index == source_index) + + if (plist[i].source_plugin_index == source_index) plist[i].source_plugin_index = -1; } } // Find if any plugin has been loaded by plugin 'source_index' -mBOOL DLLINTERNAL MPluginList::found_child_plugins(int source_index) { - int i; - - if(source_index <= 0) - return(mFALSE); - - for(i=0; i < endlist; i++) { - if(plist[i].status < PL_VALID) +mBOOL MPluginList::found_child_plugins(int source_index) +{ + if (source_index <= 0) + return mFALSE; + + for (int i = 0; i < endlist; i++) + { + if (plist[i].status < PL_VALID) continue; - if(plist[i].source_plugin_index == source_index) - return(mTRUE); + + if (plist[i].source_plugin_index == source_index) + return mTRUE; } - - return(mFALSE); + + return mFALSE; } // Try make endlist lower (called after plugin unload) -void DLLINTERNAL MPluginList::trim_list(void) { - int i,n; - - if(endlist <= 0) +void MPluginList::trim_list() +{ + if (endlist <= 0) return; - - for(i=0,n=0; i < endlist; i++) { - if(plist[i].status == PL_EMPTY) + + int n = 0; + for (int i = 0; i < endlist; i++) + { + if (plist[i].status == PL_EMPTY) continue; - n=i+1; + + n = i + 1; } - - if(n < endlist) - endlist=n; + + if (n < endlist) + endlist = n; } // Find a plugin with the given plid. // meta_errno values: // - ME_ARGUMENT null plid_t // - ME_NOTFOUND couldn't find a matching plugin -MPlugin * DLLINTERNAL MPluginList::find(plid_t id) { - int i; - - if(!id) +MPlugin *MPluginList::find(plid_t id) +{ + if (!id) RETURN_ERRNO(NULL, ME_ARGUMENT); - for(i=0; i < endlist; i++) { - if(plist[i].status < PL_VALID) + + for (int i = 0; i < endlist; i++) + { + if (plist[i].status < PL_VALID) continue; - if(plist[i].info == id) - return(&plist[i]); + + if (plist[i].info == id) + return &plist[i]; } + RETURN_ERRNO(NULL, ME_NOTFOUND); } @@ -146,21 +149,25 @@ MPlugin * DLLINTERNAL MPluginList::find(plid_t id) { // meta_errno values: // - ME_ARGUMENT null path // - ME_NOTFOUND couldn't find a matching plugin -MPlugin * DLLINTERNAL MPluginList::find(const char *findpath) { - int i; - - if(!findpath) +MPlugin *MPluginList::find(const char *findpath) +{ + if (!findpath) RETURN_ERRNO(NULL, ME_ARGUMENT); + META_DEBUG(8, ("Looking for loaded plugin with dlfnamepath: %s", findpath)); - for(i=0; i < endlist; i++) { + for (int i = 0; i < endlist; i++) + { META_DEBUG(9, ("Looking at: plugin %s loadedpath: %s", plist[i].file, plist[i].pathname)); - if(plist[i].status < PL_VALID) + if (plist[i].status < PL_VALID) continue; - if(strmatch(plist[i].pathname, findpath)) { + + if (!Q_strcmp(plist[i].pathname, findpath)) + { META_DEBUG(8, ("Found loaded plugin %s", plist[i].file)); - return(&plist[i]); + return &plist[i]; } } + META_DEBUG(8, ("No loaded plugin found with path: %s", findpath)); RETURN_ERRNO(NULL, ME_NOTFOUND); } @@ -170,344 +177,405 @@ MPlugin * DLLINTERNAL MPluginList::find(const char *findpath) { // - ME_ARGUMENT null memptr // - ME_NOTFOUND couldn't find a matching plugin // - errno's from DLFNAME() -MPlugin * DLLINTERNAL MPluginList::find_memloc(void *memptr) { -#ifdef linux - const char *dlfile; - - if(!memptr) - RETURN_ERRNO(NULL, ME_ARGUMENT); - if(!(dlfile=DLFNAME(memptr))) { - META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr)); - // meta_errno should be already set in DLFNAME - return(NULL); - } - - return(find(dlfile)); -#else +MPlugin *MPluginList::find_memloc(void *memptr) +{ +#ifdef _WIN32 DLHANDLE dlhandle; - - if(!memptr) + + if (!memptr) RETURN_ERRNO(NULL, ME_ARGUMENT); - if(!(dlhandle=get_module_handle_of_memptr(memptr))) { + + if (!(dlhandle = get_module_handle_of_memptr(memptr))) + { META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr)); RETURN_ERRNO(NULL, ME_NOTFOUND); } - - return(find(dlhandle)); + + return find(dlhandle); +#else + const char *dlfile; + + if (!memptr) + RETURN_ERRNO(NULL, ME_ARGUMENT); + + if (!(dlfile = DLFNAME(memptr))) + { + META_DEBUG(8, ("DLFNAME failed to find memloc %d", memptr)); + // meta_errno should be already set in DLFNAME + return NULL; + } + + return find(dlfile); #endif } -// Find a plugin with non-ambiguous prefix string matching desc, file, +// Find a plugin with non-ambiguous prefix string matching desc, file, // name, or logtag. // meta_errno values: // - ME_ARGUMENT null prefix // - ME_NOTFOUND couldn't find a matching plugin // - ME_NOTUNIQ found multiple matches; no unique match -MPlugin * DLLINTERNAL MPluginList::find_match(const char *prefix) { - int i, len; +MPlugin *MPluginList::find_match(const char *prefix) +{ + int len; MPlugin *iplug, *pfound; char buf[NAME_MAX]; - if(!prefix) + if (!prefix) RETURN_ERRNO(NULL, ME_ARGUMENT); - pfound=NULL; - len=Q_strlen(prefix); + + pfound = nullptr; + len = Q_strlen(prefix); safevoid_snprintf(buf, sizeof(buf), "mm_%s", prefix); - for(i=0; i < endlist; i++) { - iplug=&plist[i]; - if(iplug->status < PL_VALID) + + for (int i = 0; i < endlist; i++) + { + iplug = &plist[i]; + + if (iplug->status < PL_VALID) continue; - if(iplug->info && strncasecmp(iplug->info->name, prefix, len) == 0) { - if(pfound) - RETURN_ERRNO(NULL, ME_NOTUNIQ); - pfound=iplug; - continue; - } - else if(strncasecmp(iplug->desc, prefix, len) == 0) { - if(pfound) - RETURN_ERRNO(NULL, ME_NOTUNIQ); - pfound=iplug; - continue; - } - else if(strncasecmp(iplug->file, prefix, len) == 0) { - if(pfound) - RETURN_ERRNO(NULL, ME_NOTUNIQ); - pfound=iplug; - continue; - } - else if(strncasecmp(iplug->file, buf, Q_strlen(buf)) == 0) { - if(pfound) - RETURN_ERRNO(NULL, ME_NOTUNIQ); - pfound=iplug; - continue; - } - else if(iplug->info - && strncasecmp(iplug->info->logtag, prefix, len) == 0) + + if (iplug->info && Q_strnicmp(iplug->info->name, prefix, len) == 0) { - if(pfound) + if (pfound) RETURN_ERRNO(NULL, ME_NOTUNIQ); - pfound=iplug; + pfound = iplug; + continue; + } + else if (Q_strnicmp(iplug->desc, prefix, len) == 0) + { + if (pfound) + RETURN_ERRNO(NULL, ME_NOTUNIQ); + pfound = iplug; + continue; + } + else if (Q_strnicmp(iplug->file, prefix, len) == 0) + { + if (pfound) + RETURN_ERRNO(NULL, ME_NOTUNIQ); + pfound = iplug; + continue; + } + else if (Q_strnicmp(iplug->file, buf, Q_strlen(buf)) == 0) + { + if (pfound) + RETURN_ERRNO(NULL, ME_NOTUNIQ); + pfound = iplug; + continue; + } + else if (iplug->info && Q_strnicmp(iplug->info->logtag, prefix, len) == 0) + { + if (pfound) + RETURN_ERRNO(NULL, ME_NOTUNIQ); + pfound = iplug; continue; } } - - if(pfound) - return(pfound); + + if (pfound) + return pfound; RETURN_ERRNO(NULL, ME_NOTFOUND); } -// Find a plugin with same file, logtag, desc or significant +// Find a plugin with same file, logtag, desc or significant // prefix of file. Uses the platform_match() method of MPlugin. // meta_errno values: // - ME_ARGUMENT null prefix // - ME_NOTFOUND couldn't find a matching plugin -MPlugin * DLLINTERNAL MPluginList::find_match(MPlugin *pmatch) { - int i; +MPlugin *MPluginList::find_match(MPlugin *pmatch) +{ MPlugin *iplug, *pfound; - if(!pmatch) + if (!pmatch) RETURN_ERRNO(NULL, ME_ARGUMENT); - pfound=NULL; - for(i=0; i < endlist; i++) { - iplug=&plist[i]; - if(pmatch->platform_match(iplug)) { + + pfound = nullptr; + for (int i = 0; i < endlist; i++) + { + iplug = &plist[i]; + if (pmatch->platform_match(iplug)) + { pfound=iplug; break; } } - if(pfound) - return(pfound); - + if (pfound) + return pfound; + RETURN_ERRNO(NULL, ME_NOTFOUND); } // Add a plugin to the list. // meta_errno values: // - ME_MAXREACHED reached max plugins -MPlugin * DLLINTERNAL MPluginList::add(MPlugin *padd) { +MPlugin *MPluginList::add(MPlugin *padd) +{ int i; MPlugin *iplug; // Find either: // - a slot in the list that's not being used // - the end of the list - for(i=0; i < endlist && plist[i].status != PL_EMPTY; i++); + for (i = 0; i < endlist && plist[i].status != PL_EMPTY; i++) {} // couldn't find a slot to use - if(i==size) { - META_WARNING("Couldn't add plugin '%s' to list; reached max plugins (%d)", - padd->file, i); + if (i == size) + { + META_WARNING("Couldn't add plugin '%s' to list; reached max plugins (%d)", padd->file, i); RETURN_ERRNO(NULL, ME_MAXREACHED); } // if we found the end of the list, advance end marker - if(i==endlist) + if (i == endlist) endlist++; + iplug = &plist[i]; // copy filename into this free slot - STRNCPY(iplug->filename, padd->filename, sizeof(iplug->filename)); + Q_strncpy(iplug->filename, padd->filename, sizeof(iplug->filename) - 1); + iplug->filename[sizeof(iplug->filename) - 1] = '\0'; + // Copy file offset ptr. // Can't just copy ptr, as it points to offset in padd, which will go // away; need to point to corresponding offset in iplug. iplug->file = iplug->filename + (padd->file - padd->filename); - // copy description - STRNCPY(iplug->desc, padd->desc, sizeof(iplug->desc)); - // copy pathname - STRNCPY(iplug->pathname, padd->pathname, sizeof(iplug->pathname)); - // copy source - iplug->source=padd->source; - // copy loader-plugin - iplug->source_plugin_index=padd->source_plugin_index; - // copy status - iplug->status=padd->status; - return(iplug); -} + // copy description + Q_strncpy(iplug->desc, padd->desc, sizeof(iplug->desc) - 1); + iplug->desc[sizeof(iplug->desc) - 1] = '\0'; + + // copy pathname + Q_strncpy(iplug->pathname, padd->pathname, sizeof(iplug->pathname) - 1); + iplug->pathname[sizeof(iplug->pathname) - 1] = '\0'; + + // copy source + iplug->source = padd->source; + + // copy loader-plugin + iplug->source_plugin_index = padd->source_plugin_index; + + // copy status + iplug->status = padd->status; + + return iplug; +} // Read plugins.ini at server startup. // meta_errno values: // - ME_NOFILE ini file missing or empty -mBOOL DLLINTERNAL MPluginList::ini_startup() { +mBOOL MPluginList::ini_startup() +{ FILE *fp; char line[MAX_STRBUF_LEN]; int n, ln; MPlugin *pmatch; - if(!valid_gamedir_file(inifile)) { + if (!valid_gamedir_file(inifile)) + { META_WARNING("ini: Metamod plugins file empty or missing: %s", inifile); RETURN_ERRNO(mFALSE, ME_NOFILE); } + full_gamedir_path(inifile, inifile); - fp=fopen(inifile, "r"); - if(!fp) { - META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, - strerror(errno)); + fp = fopen(inifile, "r"); + if (!fp) + { + META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, strerror(errno)); RETURN_ERRNO(mFALSE, ME_NOFILE); } META_LOG("ini: Begin reading plugins list: %s", inifile); - for(n=0, ln=1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++) { + for (n = 0, ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++) + { // Remove line terminations. char *cp; - if((cp=Q_strrchr(line, '\r'))) - *cp='\0'; - if((cp=Q_strrchr(line, '\n'))) - *cp='\0'; + if ((cp = Q_strrchr(line, '\r'))) + *cp = '\0'; + if ((cp = Q_strrchr(line, '\n'))) + *cp = '\0'; + // Parse directly into next entry in array - if(!plist[n].ini_parseline(line)) { - if(meta_errno==ME_FORMAT) - META_WARNING("ini: Skipping malformed line %d of %s", ln, - inifile); + if (!plist[n].ini_parseline(line)) + { + if (meta_errno == ME_FORMAT) + META_WARNING("ini: Skipping malformed line %d of %s", ln, inifile); continue; } + // Check for a duplicate - an existing entry with this pathname. - if(find(plist[n].pathname)) { + if (find(plist[n].pathname)) + { // Should we check platform specific level here? - META_INFO("ini: Skipping duplicate plugin, line %d of %s: %s", - ln, inifile, plist[n].pathname); + META_INFO("ini: Skipping duplicate plugin, line %d of %s: %s", ln, inifile, plist[n].pathname); continue; } + // Check for a matching platform with different platform specifics // level. - if(NULL != (pmatch=find_match(&plist[n]))) { - if(pmatch->pfspecific >= plist[n].pfspecific) { - META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", - ln, inifile, pmatch->pfspecific, plist[n].pfspecific)); + if ((pmatch = find_match(&plist[n]))) + { + if (pmatch->pfspecific >= plist[n].pfspecific) + { + META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pmatch->pfspecific, plist[n].pfspecific)); continue; } - META_DEBUG(1, ("ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", - ln, pmatch->pfspecific, plist[n].pfspecific)); + + META_DEBUG(1, ("ini: Plugin in line %d overrides existing plugin with lower platform specific level %d, ours %d", ln, pmatch->pfspecific, plist[n].pfspecific)); //reset to empty reset_plugin(pmatch); } + plist[n].action=PA_LOAD; META_LOG("ini: Read plugin config for: %s", plist[n].desc); n++; - endlist=n; // mark end of list + endlist = n; // mark end of list } - META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", - inifile, n); + META_LOG("ini: Finished reading plugins list: %s; Found %d plugins to load", inifile, n); fclose(fp); - if(!n) { + + if (!n) + { META_WARNING("ini: Warning; no plugins found to load?"); } - return(mTRUE); + + return mTRUE; } // Re-read plugins.ini looking for added/deleted/changed plugins. // meta_errno values: // - ME_NOFILE ini file missing or empty -mBOOL DLLINTERNAL MPluginList::ini_refresh() { +mBOOL MPluginList::ini_refresh() +{ FILE *fp; char line[MAX_STRBUF_LEN]; int n, ln; MPlugin pl_temp; MPlugin *pl_found, *pl_added; - fp=fopen(inifile, "r"); - if(!fp) { - META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, - strerror(errno)); + fp = fopen(inifile, "r"); + if (!fp) + { + META_WARNING("ini: Unable to open plugins file '%s': %s", inifile, strerror(errno)); RETURN_ERRNO(mFALSE, ME_NOFILE); } META_LOG("ini: Begin re-reading plugins list: %s", inifile); - for(n=0, ln=1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++) + for (n = 0, ln = 1; !feof(fp) && fgets(line, sizeof(line), fp) && n < size; ln++) { // Remove line terminations. char *cp; - if((cp=Q_strrchr(line, '\r'))) - *cp='\0'; - if((cp=Q_strrchr(line, '\n'))) - *cp='\0'; + if ((cp = Q_strrchr(line, '\r'))) + *cp = '\0'; + + if ((cp = Q_strrchr(line, '\n'))) + *cp = '\0'; + // Parse into a temp plugin Q_memset(&pl_temp, 0, sizeof(pl_temp)); - if(!pl_temp.ini_parseline(line)) { - if(meta_errno==ME_FORMAT) - META_WARNING("ini: Skipping malformed line %d of %s", - ln, inifile); + if (!pl_temp.ini_parseline(line)) + { + if (meta_errno == ME_FORMAT) + { + META_WARNING("ini: Skipping malformed line %d of %s", ln, inifile); + } + continue; } // Try to find plugin with this pathname in the current list of // plugins. - if(!(pl_found=find(pl_temp.pathname))) { + if (!(pl_found = find(pl_temp.pathname))) + { // Check for a matching platform with higher platform specifics // level. - if(NULL != (pl_found=find_match(&pl_temp))) { - if(pl_found->pfspecific >= pl_temp.pfspecific) { - META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", - ln, inifile, pl_found->pfspecific, pl_temp.pfspecific)); + if ((pl_found = find_match(&pl_temp))) + { + if (pl_found->pfspecific >= pl_temp.pfspecific) + { + META_DEBUG(1, ("ini: Skipping plugin, line %d of %s: plugin with higher platform specific level already exists. (%d >= %d)", ln, inifile, pl_found->pfspecific, pl_temp.pfspecific)); continue; } - if(PA_LOAD == pl_found->action) { - META_DEBUG(1, ("ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", - ln, pl_found->pfspecific, pl_temp.pfspecific)); + if (PA_LOAD == pl_found->action) + { + META_DEBUG(1, ("ini: Plugin in line %d overrides loading of plugin with lower platform specific level %d, ours %d", ln, pl_found->pfspecific, pl_temp.pfspecific)); //reset to empty reset_plugin(pl_found); } - else { - META_DEBUG(1, ("ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", - ln, pl_found->pfspecific, pl_temp.pfspecific)); + else + { + META_DEBUG(1, ("ini: Plugin in line %d should override existing plugin with lower platform specific level %d, ours %d. Unable to comply.", ln, pl_found->pfspecific, pl_temp.pfspecific)); continue; } } + // new plugin; add to list - if((pl_added=add(&pl_temp))) { + if ((pl_added = add(&pl_temp))) + { // try to load this plugin at the next opportunity - pl_added->action=PA_LOAD; + pl_added->action = PA_LOAD; } else // error details logged in add() continue; } - else { + else + { // This plugin is already in the current list of plugins. // Pathname already matches. Recopy desc, if specified in // plugins.ini. - if(pl_temp.desc[0] != '<') - STRNCPY(pl_found->desc, pl_temp.desc, sizeof(pl_found->desc)); + if (pl_temp.desc[0] != '<') + { + Q_strncpy(pl_found->desc, pl_temp.desc, sizeof(pl_found->desc) - 1); + pl_found->desc[sizeof(pl_found->desc) - 1] = '\0'; + } // Check the file to see if it looks like it's been modified // since we last loaded it. - if(!pl_found->newer_file()) { - if(meta_errno==ME_NOFILE) { - META_WARNING("ini: Skipping plugin, couldn't stat file '%s': %s", - pl_found->pathname, strerror(errno)); + if (!pl_found->newer_file()) + { + if (meta_errno == ME_NOFILE) + { + META_WARNING("ini: Skipping plugin, couldn't stat file '%s': %s", pl_found->pathname, strerror(errno)); continue; } - else { + else + { // File hasn't been updated. // Keep plugin (don't let refresh() unload it). - pl_found->action=PA_KEEP; + pl_found->action = PA_KEEP; } } // Newer file on disk. - else if(pl_found->status >= PL_OPENED) { + else if (pl_found->status >= PL_OPENED) + { META_DEBUG(2, ("ini: Plugin '%s' has newer file on disk", pl_found->desc)); - pl_found->action=PA_RELOAD; + pl_found->action = PA_RELOAD; } else - META_WARNING("ini: Plugin '%s' has newer file, but unexpected status (%s)", - pl_found->desc, pl_found->str_status()); + META_WARNING("ini: Plugin '%s' has newer file, but unexpected status (%s)", pl_found->desc, pl_found->str_status()); } - if(NULL != pl_found) { + if (pl_found) + { META_LOG("ini: Read plugin config for: %s", pl_found->desc); } - else { + else + { META_LOG("ini: Read plugin config for: %s", pl_temp.desc); } + n++; } + META_LOG("ini: Finished reading plugins list: %s; Found %d plugins", inifile, n); fclose(fp); - if(!n) { + if (!n) + { META_WARNING("ini: Warning; no plugins found to load?"); } - return(mTRUE); + + return mTRUE; } // Load a plugin from plugin request. @@ -516,29 +584,33 @@ mBOOL DLLINTERNAL MPluginList::ini_refresh() { // - ME_ALREADY this plugin already loaded // - errno's from add() // - errno's from load() -MPlugin * DLLINTERNAL MPluginList::plugin_addload(plid_t plid, const char *fname, PLUG_LOADTIME now) { +MPlugin *MPluginList::plugin_addload(plid_t plid, const char *fname, PLUG_LOADTIME now) +{ MPlugin pl_temp; MPlugin *pl_found, *pl_added, *pl_loader; - + // Find loader plugin - if(!(pl_loader=find(plid))) { + if (!(pl_loader = find(plid))) + { // Couldn't find a matching file on disk META_DEBUG(1, ("Couldn't find plugin that gave this loading request!")); // meta_errno should be already set in resolve() RETURN_ERRNO(NULL, ME_BADREQ); } - + Q_memset(&pl_temp, 0, sizeof(pl_temp)); - + // copy filename - if(!pl_temp.plugin_parseline(fname, pl_loader->index)) { + if (!pl_temp.plugin_parseline(fname, pl_loader->index)) + { // parse_plugin_load doesn't return mFALSE. RETURN_ERRNO(NULL, ME_NOTFOUND); } - + // resolve given path into a file; accepts various "shortcut" // pathnames. - if(pl_temp.resolve() != mTRUE) { + if (pl_temp.resolve() != mTRUE) + { // Couldn't find a matching file on disk META_DEBUG(1, ("Couldn't resolve given path into a file: %s", pl_temp.file)); // meta_errno should be already set in resolve() @@ -547,38 +619,44 @@ MPlugin * DLLINTERNAL MPluginList::plugin_addload(plid_t plid, const char *fname // Try to find plugin with this pathname in the current list of // plugins. - if((pl_found=find(pl_temp.pathname))) { + if ((pl_found = find(pl_temp.pathname))) + { // Already in list - META_DEBUG(1, ("Plugin '%s' already in current list; file=%s desc='%s'", + META_DEBUG(1, ("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.file, pl_found->file, pl_found->desc)); RETURN_ERRNO(NULL, ME_ALREADY); } + // new plugin; add to list - if(!(pl_added=add(&pl_temp))) { + if (!(pl_added = add(&pl_temp))) + { META_DEBUG(1, ("Couldn't add plugin '%s' to list; see log", pl_temp.desc)); // meta_errno should be already set in add() - return(NULL); + return NULL; } // try to load new plugin (setting 'must load now') - pl_added->action=PA_LOAD; - if(!pl_added->load(now)) { + pl_added->action = PA_LOAD; + if (!pl_added->load(now)) + { // load failed - if(meta_errno==ME_NOTALLOWED || meta_errno==ME_DELAYED) { - META_DEBUG(1, ("Plugin '%s' couldn't attach; only allowed %s", + if (meta_errno == ME_NOTALLOWED || meta_errno == ME_DELAYED) + { + META_DEBUG(1, ("Plugin '%s' couldn't attach; only allowed %s", pl_added->desc, pl_added->str_loadable(SL_ALLOWED))); pl_added->clear(); } - else if(pl_added->status == PL_OPENED) + else if (pl_added->status == PL_OPENED) META_DEBUG(1, ("Opened plugin '%s', but failed to attach; see log", pl_added->desc)); else META_DEBUG(1, ("Couldn't load plugin '%s'; see log", pl_added->desc)); // meta_errno should be already set in load() - return(NULL); + return NULL; } + META_DEBUG(1, ("Loaded plugin '%s' successfully", pl_added->desc)); meta_errno = ME_NOERROR; - return(pl_added); + return pl_added; } // Load a plugin from a console command. @@ -588,185 +666,216 @@ MPlugin * DLLINTERNAL MPluginList::plugin_addload(plid_t plid, const char *fname // - ME_ALREADY this plugin already loaded // - errno's from add() // - errno's from load() -mBOOL DLLINTERNAL MPluginList::cmd_addload(const char *args) { +mBOOL MPluginList::cmd_addload(const char *args) +{ MPlugin pl_temp; MPlugin *pl_found, *pl_added; - + Q_memset(&pl_temp, 0, sizeof(pl_temp)); - + // XXX move back to comands_meta ? // parse into a temp plugin - if(pl_temp.cmd_parseline(args) != mTRUE) { + if (pl_temp.cmd_parseline(args) != mTRUE) + { META_CONS("Couldn't parse 'meta load' arguments: %s", args); // meta_errno should be already set in cmd_parseline() - return(mFALSE); + return mFALSE; } // resolve given path into a file; accepts various "shortcut" // pathnames. - if(pl_temp.resolve() != mTRUE) { + if (pl_temp.resolve() != mTRUE) + { // Couldn't find a matching file on disk - META_CONS("Couldn't resolve given path into a file: %s", + META_CONS("Couldn't resolve given path into a file: %s", pl_temp.file); // meta_errno should be already set in resolve() - return(mFALSE); + return mFALSE; } // Try to find plugin with this pathname in the current list of // plugins. - if((pl_found=find(pl_temp.pathname))) { + if ((pl_found=find(pl_temp.pathname))) + { // Already in list - META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", + META_CONS("Plugin '%s' already in current list; file=%s desc='%s'", pl_temp.file, pl_found->file, pl_found->desc); RETURN_ERRNO(mFALSE, ME_ALREADY); } // new plugin; add to list - if(!(pl_added=add(&pl_temp))) { + if (!(pl_added=add(&pl_temp))) + { META_CONS("Couldn't add plugin '%s' to list; see log", pl_temp.desc); // meta_errno should be already set in add() - return(mFALSE); + return mFALSE; } // try to load new plugin pl_added->action=PA_LOAD; - if(!pl_added->load(PT_ANYTIME)) { + if (!pl_added->load(PT_ANYTIME)) + { // load failed - if(meta_errno==ME_DELAYED) - META_CONS("Loaded plugin '%s', but will wait to become active, %s", - pl_added->desc, pl_added->str_loadable(SL_ALLOWED)); - else if(meta_errno==ME_NOTALLOWED) { - META_CONS("Plugin '%s' couldn't attach; only allowed %s", - pl_added->desc, pl_added->str_loadable(SL_ALLOWED)); + if (meta_errno==ME_DELAYED) + META_CONS("Loaded plugin '%s', but will wait to become active, %s", pl_added->desc, pl_added->str_loadable(SL_ALLOWED)); + else if (meta_errno==ME_NOTALLOWED) + { + META_CONS("Plugin '%s' couldn't attach; only allowed %s", pl_added->desc, pl_added->str_loadable(SL_ALLOWED)); pl_added->clear(); } - else if(pl_added->status == PL_OPENED) + else if (pl_added->status == PL_OPENED) META_CONS("Opened plugin '%s', but failed to attach; see log", pl_added->desc); else META_CONS("Couldn't load plugin '%s'; see log", pl_added->desc); + show(); // meta_errno should be already set in load() - return(mFALSE); + return mFALSE; } + META_CONS("Loaded plugin '%s' successfully", pl_added->desc); show(); - return(mTRUE); + return mTRUE; } // Load plugins at startup. // meta_errno values: // - errno's from ini_startup() -mBOOL DLLINTERNAL MPluginList::load() { - int i, n; - - if(!ini_startup()) { +mBOOL MPluginList::load() +{ + if (!ini_startup()) + { META_WARNING("Problem loading plugins.ini: %s", inifile); // meta_errno should be already set in ini_startup() - return(mFALSE); + return mFALSE; } META_LOG("dll: Loading plugins..."); - for(i=0, n=0; i < endlist; i++) { - if(plist[i].status < PL_VALID) + + int n = 0; + for (int i = 0; i < endlist; i++) + { + if (plist[i].status < PL_VALID) continue; - if(plist[i].load(PT_STARTUP) == mTRUE) + + if (plist[i].load(PT_STARTUP) == mTRUE) n++; else // all plugins should be loadable at startup... META_WARNING("dll: Failed to load plugin '%s'", plist[i].file); } + META_LOG("dll: Finished loading %d plugins", n); - return(mTRUE); + return mTRUE; } // Update list of loaded plugins from ini file, and load any new/changed plugins. // meta_errno values: // - errno's from ini_refresh() -mBOOL DLLINTERNAL MPluginList::refresh(PLUG_LOADTIME now) { - int i, ndone=0, nkept=0, nloaded=0, nunloaded=0, nreloaded=0, ndelayed=0; +mBOOL MPluginList::refresh(PLUG_LOADTIME now) +{ + int i, ndone = 0, nkept = 0, nloaded = 0, nunloaded = 0, nreloaded = 0, ndelayed = 0; MPlugin *iplug; - if(!ini_refresh()) { + if (!ini_refresh()) + { META_WARNING("dll: Problem reloading plugins.ini: %s", inifile); // meta_errno should be already set in ini_refresh() - return(mFALSE); + return mFALSE; } META_LOG("dll: Updating plugins..."); - for(i=0; i < endlist; i++) { - iplug=&plist[i]; - if(iplug->status < PL_VALID) + for (i = 0; i < endlist; i++) + { + iplug = &plist[i]; + + if (iplug->status < PL_VALID) continue; - switch(iplug->action) { - case PA_KEEP: - META_DEBUG(1, ("Keeping plugin '%s'", iplug->desc)); - iplug->action=PA_NONE; - nkept++; - break; - case PA_LOAD: - META_DEBUG(1, ("Loading plugin '%s'", iplug->desc)); - if(iplug->load(now)) - nloaded++; - else if(meta_errno==ME_DELAYED) - ndelayed++; - break; - case PA_RELOAD: - META_DEBUG(1, ("Reloading plugin '%s'", iplug->desc)); - if(iplug->reload(now, PNL_FILE_NEWER)) - nreloaded++; - else if(meta_errno==ME_DELAYED) - ndelayed++; - break; - case PA_NONE: - // If previously loaded from ini, but apparently removed from new ini. - if(iplug->source==PS_INI && iplug->status >= PL_RUNNING) { - META_DEBUG(1, ("Unloading plugin '%s'", iplug->desc)); - iplug->action=PA_UNLOAD; - if(iplug->unload(now, PNL_INI_DELETED, PNL_INI_DELETED)) - nunloaded++; - else if(meta_errno==ME_DELAYED) - ndelayed++; - } - break; - case PA_ATTACH: - // Previously requested attach, but was delayed? - META_DEBUG(1, ("Retrying attach plugin '%s'", iplug->desc)); - if(iplug->retry(now, PNL_DELAYED)) - nloaded++; - else if(meta_errno==ME_DELAYED) - ndelayed++; - break; - case PA_UNLOAD: - // Previously requested unload, but was delayed? - META_DEBUG(1, ("Retrying unload plugin '%s'", iplug->desc)); - if(iplug->retry(now, PNL_DELAYED)) + + switch (iplug->action) + { + case PA_KEEP: + META_DEBUG(1, ("Keeping plugin '%s'", iplug->desc)); + iplug->action = PA_NONE; + nkept++; + break; + case PA_LOAD: + META_DEBUG(1, ("Loading plugin '%s'", iplug->desc)); + + if (iplug->load(now)) + nloaded++; + + else if (meta_errno == ME_DELAYED) + ndelayed++; + break; + case PA_RELOAD: + META_DEBUG(1, ("Reloading plugin '%s'", iplug->desc)); + + if (iplug->reload(now, PNL_FILE_NEWER)) + nreloaded++; + + else if (meta_errno == ME_DELAYED) + ndelayed++; + break; + case PA_NONE: + // If previously loaded from ini, but apparently removed from new ini. + if (iplug->source == PS_INI && iplug->status >= PL_RUNNING) + { + META_DEBUG(1, ("Unloading plugin '%s'", iplug->desc)); + iplug->action = PA_UNLOAD; + + if (iplug->unload(now, PNL_INI_DELETED, PNL_INI_DELETED)) nunloaded++; - else if(meta_errno==ME_DELAYED) + + else if (meta_errno == ME_DELAYED) ndelayed++; - break; - case PA_NULL: - META_WARNING("dll: Unexpected action for plugin '%s': '%s'", iplug->desc, iplug->str_action()); - break; - default: - META_WARNING("dll: Unrecognized action for plugin '%s': '%s'", iplug->desc, iplug->str_action()); - break; + } + break; + case PA_ATTACH: + // Previously requested attach, but was delayed? + META_DEBUG(1, ("Retrying attach plugin '%s'", iplug->desc)); + + if (iplug->retry(now, PNL_DELAYED)) + nloaded++; + + else if (meta_errno == ME_DELAYED) + ndelayed++; + break; + case PA_UNLOAD: + // Previously requested unload, but was delayed? + META_DEBUG(1, ("Retrying unload plugin '%s'", iplug->desc)); + + if (iplug->retry(now, PNL_DELAYED)) + nunloaded++; + + else if (meta_errno == ME_DELAYED) + ndelayed++; + break; + case PA_NULL: + META_WARNING("dll: Unexpected action for plugin '%s': '%s'", iplug->desc, iplug->str_action()); + break; + default: + META_WARNING("dll: Unrecognized action for plugin '%s': '%s'", iplug->desc, iplug->str_action()); + break; } ndone++; } - META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", - ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed); - return(mTRUE); + + META_LOG("dll: Finished updating %d plugins; kept %d, loaded %d, unloaded %d, reloaded %d, delayed %d", ndone, nkept, nloaded, nunloaded, nreloaded, ndelayed); + return mTRUE; } // Re-enable any plugins currently paused. // meta_errno values: // - none -void DLLINTERNAL MPluginList::unpause_all(void) { - int i; +void MPluginList::unpause_all() +{ MPlugin *iplug; - for(i=0; i < endlist; i++) { - iplug=&plist[i]; - if(iplug->status==PL_PAUSED) + for (int i = 0; i < endlist; i++) + { + iplug = &plist[i]; + + if (iplug->status == PL_PAUSED) iplug->unpause(); } } @@ -775,12 +884,14 @@ void DLLINTERNAL MPluginList::unpause_all(void) { // until changelevel. // meta_errno values: // - none -void DLLINTERNAL MPluginList::retry_all(PLUG_LOADTIME now) { - int i; +void MPluginList::retry_all(PLUG_LOADTIME now) +{ MPlugin *iplug; - for(i=0; i < endlist; i++) { - iplug=&plist[i]; - if(iplug->action != PA_NONE) + for (int i = 0; i < endlist; i++) + { + iplug = &plist[i]; + + if (iplug->action != PA_NONE) iplug->retry(now, PNL_DELAYED); } } @@ -788,74 +899,85 @@ void DLLINTERNAL MPluginList::retry_all(PLUG_LOADTIME now) { // List plugins and information about them in a formatted table. // meta_errno values: // - none -void DLLINTERNAL MPluginList::show(int source_index) { - int i, n=0, r=0; +void MPluginList::show(int source_index) +{ + int n = 0, r = 0; MPlugin *pl; - char desc[15+1], file[16+1], vers[7+1]; // plus 1 for term null - - if(source_index <= 0) + char desc[15 + 1], file[16 + 1], vers[7 + 1]; // plus 1 for term null + + if (source_index <= 0) META_CONS("Currently loaded plugins:"); else META_CONS("Child plugins:"); - - META_CONS(" %*s %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", - WIDTH_MAX_PLUGINS, "", - sizeof(desc)-1, "description", - "stat", "pend", - sizeof(file)-1, "file", sizeof(vers)-1, "ers", - 2+WIDTH_MAX_PLUGINS, "src", - "load ", "unlod"); - - for(i=0; i < endlist; i++) { - pl=&plist[i]; - if(pl->status < PL_VALID) + + META_CONS(" %*s %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, "", sizeof(desc) - 1, "description", "stat", "pend", + sizeof(file) - 1, "file", sizeof(vers) - 1, "ers", 2 + WIDTH_MAX_PLUGINS, "src", "load ", "unlod"); + + for (int i = 0; i < endlist; i++) + { + pl = &plist[i]; + if (pl->status < PL_VALID) continue; - if(source_index > 0 && pl->source_plugin_index != source_index) + + if (source_index > 0 && pl->source_plugin_index != source_index) continue; - STRNCPY(desc, pl->desc, sizeof(desc)); - STRNCPY(file, pl->file, sizeof(file)); - if(pl->info && pl->info->version) - STRNCPY(vers, pl->info->version, sizeof(vers)); - else - STRNCPY(vers, " -", sizeof(vers)); - META_CONS(" [%*d] %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", - WIDTH_MAX_PLUGINS, pl->index, - sizeof(desc)-1, desc, - pl->str_status(ST_SHOW), pl->str_action(SA_SHOW), - sizeof(file)-1, file, sizeof(vers)-1, vers, - 2+WIDTH_MAX_PLUGINS, pl->str_source(SO_SHOW), - pl->str_loadable(SL_SHOW), pl->str_unloadable(SL_SHOW)); - if(pl->status == PL_RUNNING) + + Q_strncpy(desc, pl->desc, sizeof(desc) - 1); + desc[sizeof(desc) - 1] = '\0'; + + Q_strncpy(file, pl->file, sizeof(file) - 1); + file[sizeof(file) - 1] = '\0'; + + if (pl->info && pl->info->version) + { + Q_strncpy(vers, pl->info->version, sizeof(vers) - 1); + vers[sizeof(vers) - 1] = '\0'; + } + else + { + Q_strncpy(vers, " -", sizeof(vers) - 1); + vers[sizeof(vers) - 1] = '\0'; + } + + META_CONS(" [%*d] %-*s %-4s %-4s %-*s v%-*s %-*s %-5s %-5s", WIDTH_MAX_PLUGINS, pl->index, + sizeof(desc) - 1, desc, pl->str_status(ST_SHOW), pl->str_action(SA_SHOW), sizeof(file) - 1, file, sizeof(vers) - 1, vers, + 2 + WIDTH_MAX_PLUGINS, pl->str_source(SO_SHOW), pl->str_loadable(SL_SHOW), pl->str_unloadable(SL_SHOW)); + + if (pl->status == PL_RUNNING) r++; n++; } - + META_CONS("%d plugins, %d running", n, r); } // List plugins and information to Player/client entity. Differs from the // "meta list" console command in that: // - Shows only "running" plugins, skipping any failed or paused plugins. -// - Limited info about each plugin, mostly the "public" info (name, author, +// - Limited info about each plugin, mostly the "public" info (name, author, // etc). // meta_errno values: // - none -void DLLINTERNAL MPluginList::show_client(edict_t *pEntity) { - int i, n=0; +void MPluginList::show_client(edict_t *pEntity) +{ + int n = 0; MPlugin *pl; META_CLIENT(pEntity, "Currently running plugins:"); - for(i=0; i < endlist; i++) { - pl=&plist[i]; - if(pl->status != PL_RUNNING || !pl->info) + + for (int i = 0; i < endlist; i++) + { + pl = &plist[i]; + if (pl->status != PL_RUNNING || !pl->info) continue; + n++; - META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", - n, - pl->info->name ? pl->info->name : "", - pl->info->version ? pl->info->version : "", - pl->info->date ? pl->info->date : "<../../..>", - pl->info->author ? pl->info->author : "", - pl->info->url ? pl->info->url : ""); + META_CLIENT(pEntity, " [%3d] %s, v%s, %s, by %s, see %s", n, + pl->info->name ? pl->info->name : "", + pl->info->version ? pl->info->version : "", + pl->info->date ? pl->info->date : "<../../..>", + pl->info->author ? pl->info->author : "", + pl->info->url ? pl->info->url : ""); } + META_CLIENT(pEntity, "%d plugins", n); } diff --git a/metamod/src/mlist.h b/metamod/src/mlist.h new file mode 100644 index 0000000..45f6f94 --- /dev/null +++ b/metamod/src/mlist.h @@ -0,0 +1,50 @@ +#pragma once + +#include "types_meta.h" // mBOOL +#include "mplugin.h" // class MPlugin +#include "plinfo.h" // plid_t, etc +#include "new_baseclass.h" + +// Max number of plugins we can manage. This is an arbitrary, fixed number, +// for convenience. It would probably be better to dynamically grow the +// list as needed, but we do this for now. +#define MAX_PLUGINS 50 + +// Width required to printf above MAX, for show() functions. +#define WIDTH_MAX_PLUGINS 2 + +// A list of plugins. +class MPluginList: public class_metamod_new { +public: + MPluginList(const char *ifile); + + void reset_plugin(MPlugin *pl_find); + MPlugin *find(int pindex); // find by index + MPlugin *find(const char *findpath); // find by pathname + MPlugin *find(plid_t id); // find by plid_t + MPlugin *find(DLHANDLE handle); // find by handle + MPlugin *find_memloc(void *memptr); // find by memory location + MPlugin *find_match(const char *prefix); // find by partial prefix match + MPlugin *find_match(MPlugin *pmatch); // find by platform_match() + MPlugin *add(MPlugin *padd); + mBOOL found_child_plugins(int source_index); + void clear_source_plugin_index(int source_index); + void trim_list(); + mBOOL ini_startup(); // read inifile at startup + mBOOL ini_refresh(); // re-read inifile + mBOOL cmd_addload(const char *args); // load from console command + MPlugin *plugin_addload(plid_t plid, const char *fname, PLUG_LOADTIME now); //load from plugin + mBOOL load(); // load the list, at startup + mBOOL refresh(PLUG_LOADTIME now); // update from re-read inifile + void unpause_all(); // unpause any paused plugins + void retry_all(PLUG_LOADTIME now); // retry any pending plugin actions + void show(int source_index); // list plugins to console + void show() { show(-1); }; // list plugins to console + void show_client(edict_t *pEntity); // list plugins to player client + +public: + MPlugin plist[MAX_PLUGINS]; // array of plugins + int size; // size of list, ie MAX_PLUGINS + int endlist; // index of last used entry + char inifile[PATH_MAX]; // full pathname +}; diff --git a/metamod/src/mm_pextensions.h b/metamod/src/mm_pextensions.h new file mode 100644 index 0000000..cb7ee22 --- /dev/null +++ b/metamod/src/mm_pextensions.h @@ -0,0 +1,80 @@ +#pragma once + +#include "plinfo.h" // plid_t +#include "meta_api.h" // PLUG_LOADTIME +/* + +How to use: + 1. Add new export function 'Meta_PExtGiveFnptrs' to your plugin file. + 'Meta_PExtGiveFnptrs' will be called right after 'Meta_Query' call. + 2. Meta_PExtGiveFnptrs is called with interface version 'META_PEXT_VERSION' + and pointer to extension function table. + 3. Meta_PExtGiveFnptrs should return plugin's interface version. + 4. !NOTE! Metamod will not stop loading plugin even if plugin returns + interface version greater than current. Plugin should disable itself in + this kind of situation. + +Example: + #include "mm_pextensions.h" + + pextension_funcs_t *gpMetaPExtFuncs; + + int Meta_PExtGiveFnptrs(int interfaceVersion, pextension_funcs_t *pMetaPExtFuncs) { + if (interfaceVersion < META_PEXT_VERSION) { + LOG_DEVELOPER(PLID, "Error! Metamod is too old, please update!"); + gpMetaPExtFuncs = NULL; + + return META_PEXT_VERSION; + } + + gpMetaPExtFuncs = pMetaPExtFuncs; + + return META_PEXT_VERSION; + } + +Callback functions: + - int PEXT_LOAD_PLUGIN_BY_NAME(PLID, const char *cmdline, PLUG_LOADTIME now, void **plugin_handle); + Parses 'cmdline' as metamod would parse 'meta load ' and loads found + plugin. If 'plugin_handle' is set, metamod writes module handle of loaded + plugin at it. + Returns zero on success. + For error codes see 'META_ERRNO' in 'types_meta.h'. + + - int PEXT_UNLOAD_PLUGIN_BY_NAME(PLID, const char *cmdline, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); + Parses 'cmdline' as metamod would parse 'meta unload ' and + unloads found plugin. + Returns zero on success. + For error codes see 'META_ERRNO' in 'types_meta.h'. + + - int PEXT_UNLOAD_PLUGIN_BY_HANDLE(PLID, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); + Unloads plugin with 'plugin_handle'. + Returns zero on success. + For error codes see 'META_ERRNO' in 'types_meta.h'. + + !NOTE! Plugin cannot unload itself! +*/ + +// Interface version +// 1: first version. Used in p13 +// 2: Complete remake (p14): +// pfnLoadMetaPluginByName +// pfnUnloadMetaPluginByName +// pfnUnloadMetaPluginByHandle +// v2 is locked now. Don't modify old functions. If you add new functions, increase META_PEXT_VERSION. +#define META_PEXT_VERSION 2 + +// Meta PExtension Function table type. +typedef struct pextension_funcs_s { + int (*pfnLoadMetaPluginByName)(plid_t plid, const char *cmdline, PLUG_LOADTIME now, void **plugin_handle); + int (*pfnUnloadMetaPluginByName)(plid_t plid, const char *cmdline, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); + int (*pfnUnloadMetaPluginByHandle)(plid_t plid, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); +} pextension_funcs_t; + +// Convenience macros for MetaPExtension functions. +#define PEXT_LOAD_PLUGIN_BY_NAME (*gpMetaPExtFuncs->pfnLoadMetaPluginByName) +#define PEXT_UNLOAD_PLUGIN_BY_NAME (*gpMetaPExtFuncs->pfnUnloadMetaPluginByName) +#define PEXT_UNLOAD_PLUGIN_BY_HANDLE (*gpMetaPExtFuncs->pfnUnloadMetaPluginByHandle) + +// Give plugin extension function table. +C_DLLEXPORT int Meta_PExtGiveFnptrs(int interfaceVersion, pextension_funcs_t *pMetaPExtFuncs); +typedef int (*META_GIVE_PEXT_FUNCTIONS_FN) (int interfaceVersion, pextension_funcs_t *pMetaPExtFuncs); diff --git a/src/mplayer.cpp b/metamod/src/mplayer.cpp similarity index 51% rename from src/mplayer.cpp rename to metamod/src/mplayer.cpp index a695401..8cb4669 100644 --- a/src/mplayer.cpp +++ b/metamod/src/mplayer.cpp @@ -1,68 +1,60 @@ -#include // strdup() -#include // always -#include "mplayer.h" // me -#include "sdk_util.h" // ENTINDEX() -#include "metamod.h" // gpGlobals +#include "precompiled.h" // Constructor MPlayer::MPlayer() : isQueried(mFALSE), - cvarName(NULL) + cvarName(nullptr) { } - // Destructor MPlayer::~MPlayer() { - if(cvarName) { + if (cvarName) { free(cvarName); } } - // Copy constructor MPlayer::MPlayer(const MPlayer& rhs) : isQueried(rhs.isQueried), - cvarName(NULL) + cvarName(nullptr) { - if(rhs.cvarName) { + if (rhs.cvarName) { cvarName = strdup(rhs.cvarName); } } - // Assignment operator -MPlayer& DLLINTERNAL MPlayer::operator=(const MPlayer& rhs) +MPlayer& MPlayer::operator=(const MPlayer& rhs) { isQueried = rhs.isQueried; - if(cvarName) { + if (cvarName) { free(cvarName); } - cvarName = NULL; - if(rhs.cvarName) { + cvarName = nullptr; + if (rhs.cvarName) { cvarName = strdup(rhs.cvarName); } return *this; } - // Mark a player as querying a client cvar and stores the cvar name // meta_errno values: // - ME_ARGUMENT cvar is NULL -void DLLINTERNAL MPlayer::set_cvar_query(const char *cvar) +void MPlayer::set_cvar_query(const char *cvar) { // Do not allow NULL as queried cvar since we use this as // return value in is_querying_cvar as indication if a // client cvar is queried. - if(!cvar) + if (!cvar) { meta_errno = ME_ARGUMENT; return; } isQueried = mTRUE; - if(cvarName) { + if (cvarName) { free(cvarName); } cvarName = strdup(cvar); @@ -70,52 +62,54 @@ void DLLINTERNAL MPlayer::set_cvar_query(const char *cvar) // Unmark player as querying a client cvar -void DLLINTERNAL MPlayer::clear_cvar_query(const char* /*cvar*/) +void MPlayer::clear_cvar_query(const char* /*cvar*/) { isQueried = mFALSE; - if(cvarName) + if (cvarName) { free(cvarName); - cvarName = NULL; + cvarName = nullptr; } } // Check if a client cvar is queried for this player // Returns NULL if not // or the name of the cvar. -const char * DLLINTERNAL MPlayer::is_querying_cvar(void) +const char *MPlayer::is_querying_cvar() { - if(isQueried) + if (isQueried) { - return(cvarName); + return cvarName; } - return(NULL); + + return nullptr; } // Mark a player as querying a client cvar and stores the cvar name // meta_errno values: // - ME_ARGUMENT cvar is NULL -void DLLINTERNAL MPlayerList::set_player_cvar_query(const edict_t *pEntity, const char *cvar) +void MPlayerList::set_player_cvar_query(const edict_t *pEntity, const char *cvar) { - int indx = ENTINDEX(const_cast(pEntity)); - if(indx < 1 || indx >= MPlayerList::NUM_SLOTS) + int indx = ENTINDEX(const_cast(pEntity)); + if (indx < 1 || indx > gpGlobals->maxClients) return; //maybe output a message? + players[indx].set_cvar_query(cvar); } // Unmark player as querying a client cvar -void DLLINTERNAL MPlayerList::clear_player_cvar_query(const edict_t *pEntity, const char *cvar) +void MPlayerList::clear_player_cvar_query(const edict_t *pEntity, const char *cvar) { - int indx = ENTINDEX(const_cast(pEntity)); - if(indx < 1 || indx >= MPlayerList::NUM_SLOTS) + int indx = ENTINDEX(const_cast(pEntity)); + if (indx < 1 || indx > gpGlobals->maxClients) return; //maybe output a message? + players[indx].clear_cvar_query(cvar); } - -void DLLINTERNAL MPlayerList::clear_all_cvar_queries(void) +void MPlayerList::clear_all_cvar_queries() { - for(int indx=1; indx < MPlayerList::NUM_SLOTS; ++indx) + for (int indx = 1; indx < gpGlobals->maxClients; ++indx) { players[indx].clear_cvar_query(); } @@ -126,12 +120,13 @@ void DLLINTERNAL MPlayerList::clear_all_cvar_queries(void) // or the name of the cvar. // meta_errno values: // - ME_NOTFOUND invalid entity -const char* DLLINTERNAL MPlayerList::is_querying_cvar(const edict_t *pEntity) +const char *MPlayerList::is_querying_cvar(const edict_t *pEntity) { - int indx = ENTINDEX(const_cast(pEntity)); - if(indx < 1 || indx > gpGlobals->maxClients) + int indx = ENTINDEX(const_cast(pEntity)); + if (indx < 1 || indx > gpGlobals->maxClients) { - RETURN_ERRNO(NULL, ME_NOTFOUND); + RETURN_ERRNO(nullptr, ME_NOTFOUND); } - return(players[indx].is_querying_cvar()); + + return players[indx].is_querying_cvar(); } diff --git a/metamod/src/mplayer.h b/metamod/src/mplayer.h new file mode 100644 index 0000000..b47ce7a --- /dev/null +++ b/metamod/src/mplayer.h @@ -0,0 +1,38 @@ +#pragma once + +#include "plinfo.h" // plugin_info_t, etc +#include "mutil.h" // query_callback_t +#include "types_meta.h" // mBOOL +#include "new_baseclass.h" // class_metamod_new + +// Info on an individual player +class MPlayer : public class_metamod_new +{ +private: + mBOOL isQueried; // is this player currently queried for a cvar value + char *cvarName; // name of the cvar if getting queried + MPlayer (const MPlayer&); + MPlayer& operator=(const MPlayer&); + +public: + MPlayer(); + ~MPlayer(); + void set_cvar_query(const char *cvar); // mark this player as querying a client cvar + void clear_cvar_query(const char *cvar = nullptr); // unmark this player as querying a client cvar + const char *is_querying_cvar(); // check if a player is querying a cvar. returns + // NULL if not or the name of the cvar +}; + +// A list of players. The number of max players is fixed and small enough +// to use an array. +class MPlayerList +{ +private: + MPlayer players[MAX_CLIENTS + 1]; // array of players + +public: + void set_player_cvar_query(const edict_t *pEntity, const char *cvar); + void clear_player_cvar_query(const edict_t *pEntity, const char *cvar = nullptr); + void clear_all_cvar_queries(); + const char *is_querying_cvar(const edict_t *pEntity); +}; diff --git a/src/mplugin.cpp b/metamod/src/mplugin.cpp similarity index 68% rename from src/mplugin.cpp rename to metamod/src/mplugin.cpp index 8b4a218..0ad7531 100644 --- a/src/mplugin.cpp +++ b/metamod/src/mplugin.cpp @@ -1,67 +1,59 @@ -#include // errno, etc -#include // malloc, etc -#include // stat -#include // stat -#include // always -#include "mplugin.h" // me -#include "metamod.h" // GameDLL, etc -#include "mreg.h" // MRegCmdList::show(int), etc -#include "h_export.h" // GIVE_ENGINE_FUNCTIONS_FN, etc -#include "dllapi.h" // FN_GAMEINIT, etc -#include "support_meta.h" // full_gamedir_path, -#include "types_meta.h" // mBOOL -#include "log_meta.h" // logging functions, etc -#include "osdep.h" // win32 snprintf, is_absolute_path, -#include "mm_pextensions.h" - +#include "precompiled.h" // Parse a line from plugins.ini into a plugin. // meta_errno values: // - ME_COMMENT ignored commented line // - ME_FORMAT invalid line format // - ME_OSNOTSUP plugin is not for this OS -mBOOL DLLINTERNAL MPlugin::ini_parseline(const char *line) { +mBOOL MPlugin::ini_parseline(const char *line) +{ char *token; char *ptr_token; char *cp; char *tmp_line; - // - tmp_line=strdup(line); - if(!tmp_line) + tmp_line = strdup(line); + if (!tmp_line) RETURN_ERRNO(mFALSE, ME_NOMEM); // skip whitespace at start of line - while(*tmp_line==' ' || *tmp_line=='\t') tmp_line++; + while (*tmp_line == ' ' || *tmp_line == '\t') tmp_line++; // remove whitespace at end of line cp = tmp_line + Q_strlen(tmp_line) -1; - while(*cp==' ' || *cp=='\t') *cp--='\0'; + while (*cp == ' ' || *cp == '\t') *cp-- = '\0'; // skip empty lines - if(tmp_line[0]=='\0') { + if (tmp_line[0] == '\0') + { META_DEBUG(7, ("ini: Ignoring empty line: %s", tmp_line)); free(tmp_line); RETURN_ERRNO(mFALSE, ME_BLANK); } - if(tmp_line[0]=='#' || tmp_line[0]==';' || Q_strstr(tmp_line, "//")==tmp_line) { + if (tmp_line[0] == '#' || tmp_line[0] == ';' || Q_strstr(tmp_line, "//") == tmp_line) + { META_DEBUG(7, ("ini: Ignoring commented line: %s", tmp_line)); free(tmp_line); RETURN_ERRNO(mFALSE, ME_COMMENT); } - + // grab platform ("win32" or "linux") - token=strtok_r(tmp_line, " \t", &ptr_token); - if(!token) { + token = strtok_r(tmp_line, " \t", &ptr_token); + if (!token) + { free(tmp_line); RETURN_ERRNO(mFALSE, ME_FORMAT); } - if(strcasecmp(token, PLATFORM) == 0) { - pfspecific=0; - } else if(strcasecmp(token, PLATFORM_SPC) == 0) { - pfspecific=1; - } else { + if (!Q_stricmp(token, PLATFORM)) + { + pfspecific = 0; + } else if (!Q_stricmp(token, PLATFORM_SPC)) + { + pfspecific = 1; + } + else + { // plugin is not for this OS META_DEBUG(7, ("ini: Ignoring entry for %s", token)); free(tmp_line); @@ -69,28 +61,35 @@ mBOOL DLLINTERNAL MPlugin::ini_parseline(const char *line) { } // grab filename - token=strtok_r(NULL, " \t\r\n", &ptr_token); - if(!token) { + token = strtok_r(NULL, " \t\r\n", &ptr_token); + if (!token) + { free(tmp_line); RETURN_ERRNO(mFALSE, ME_FORMAT); } - STRNCPY(filename, token, sizeof(filename)); + + Q_strncpy(filename, token, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + normalize_pathname(filename); // Store name of just the actual _file_, without dir components. - cp=Q_strrchr(filename, '/'); - if(cp) - file=cp+1; + cp = Q_strrchr(filename, '/'); + if (cp) + file = cp + 1; else - file=filename; + file = filename; // Grab description. // Just get the the rest of the line, minus line-termination. - token=strtok_r(NULL, "\n\r", &ptr_token); - if(token) { + token = strtok_r(NULL, "\n\r", &ptr_token); + if (token) + { token=token+strspn(token, " \t"); // skip whitespace - STRNCPY(desc, token, sizeof(desc)); + Q_strncpy(desc, token, sizeof(desc) - 1); + desc[sizeof(desc) - 1] = '\0'; } - else { + else + { // If no description is specified, temporarily use plugin file, // until plugin can be queried, and desc replaced with info->name. safevoid_snprintf(desc, sizeof(desc), "<%s>", file); @@ -100,38 +99,43 @@ mBOOL DLLINTERNAL MPlugin::ini_parseline(const char *line) { // backslashes, etc). full_gamedir_path(filename, pathname); - source=PS_INI; - status=PL_VALID; - + source = PS_INI; + status = PL_VALID; + free(tmp_line); - return(mTRUE); + return mTRUE; } // Parse a line from console "load" command into a plugin. // meta_errno values: // - ME_FORMAT invalid line format -mBOOL DLLINTERNAL MPlugin::cmd_parseline(const char *line) { +mBOOL MPlugin::cmd_parseline(const char *line) +{ char buf[NAME_MAX + PATH_MAX + MAX_DESC_LEN]; char *token; char *ptr_token; char *cp; - STRNCPY(buf, line, sizeof(buf)); + Q_strncpy(buf, line, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; // remove "load" token=strtok_r(buf, " \t", &ptr_token); - if(!token) + if (!token) RETURN_ERRNO(mFALSE, ME_FORMAT); // grab filename - token=strtok_r(NULL, " \t", &ptr_token); - if(!token) + token = strtok_r(NULL, " \t", &ptr_token); + if (!token) RETURN_ERRNO(mFALSE, ME_FORMAT); - STRNCPY(filename, token, sizeof(filename)); + + Q_strncpy(filename, token, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + normalize_pathname(filename); // store name of just the actual _file_, without dir components cp=Q_strrchr(filename, '/'); - if(cp) + if (cp) file=cp+1; else file=filename; @@ -139,11 +143,14 @@ mBOOL DLLINTERNAL MPlugin::cmd_parseline(const char *line) { // Grab description. // Specify no delimiter chars, as we just want the rest of the line. token=strtok_r(NULL, "", &ptr_token); - if(token) { - token=token+strspn(token, " \t"); // skip whitespace - STRNCPY(desc, token, sizeof(desc)); + if (token) { + token = token + strspn(token, " \t"); // skip whitespace + + Q_strncpy(desc, token, sizeof(desc) - 1); + desc[sizeof(desc) - 1] = '\0'; } - else { + else + { // if no description is specified, temporarily use plugin file, // until plugin can be queried, and desc replaced with info->name. safevoid_snprintf(desc, sizeof(desc), "<%s>", file); @@ -155,22 +162,24 @@ mBOOL DLLINTERNAL MPlugin::cmd_parseline(const char *line) { source=PS_CMD; status=PL_VALID; - return(mTRUE); + return mTRUE; } // Parse a filename string from PEXT_LOAD_PLUGIN_BY_* function into a plugin. // meta_errno values: -mBOOL DLLINTERNAL MPlugin::plugin_parseline(const char *fname, int loader_index) { +mBOOL MPlugin::plugin_parseline(const char *fname, int loader_index) +{ char *cp; - + source_plugin_index = loader_index; - - // - STRNCPY(filename, fname, sizeof(filename)); + + Q_strncpy(filename, fname, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + normalize_pathname(filename); // store name of just the actual _file_, without dir components cp=Q_strrchr(filename, '/'); - if(cp) + if (cp) file=cp+1; else file=filename; @@ -178,51 +187,59 @@ mBOOL DLLINTERNAL MPlugin::plugin_parseline(const char *fname, int loader_index) // Grab description. // Temporarily use plugin file, until plugin can be queried, and desc replaced with info->name. safevoid_snprintf(desc, sizeof(desc), "<%s>", file); - + // Make full pathname (from gamedir if relative, remove "..", // backslashes, etc). full_gamedir_path(filename, pathname); - + source=PS_PLUGIN; status=PL_VALID; - return(mTRUE); + return mTRUE; } // Make sure this plugin has the necessary minimal information. // meta_errno values: // - ME_ARGUMENT missing necessary fields in plugin -mBOOL DLLINTERNAL MPlugin::check_input(void) { +mBOOL MPlugin::check_input() +{ // doublecheck our input/state - if(status < PL_VALID) { + if (status < PL_VALID) + { META_WARNING("dll: Tried to operate on plugin[%d] with a non-valid status (%d)", index, str_status()); RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(!file || !file[0]) { - META_WARNING("dll: Tried to operate on plugin[%d] with an empty file", - index); + + if (!file || !file[0]) + { + META_WARNING("dll: Tried to operate on plugin[%d] with an empty file", index); RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(!filename[0]) { - META_WARNING("dll: Tried to operate on plugin[%d] with an empty filename", - index); + + if (!filename[0]) + { + META_WARNING("dll: Tried to operate on plugin[%d] with an empty filename", index); RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(!pathname[0]) { - META_WARNING("dll: Tried to operate on plugin[%d] with an empty pathname", - index); + + if (!pathname[0]) + { + META_WARNING("dll: Tried to operate on plugin[%d] with an empty pathname", index); RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(!desc[0]) { + + if (!desc[0]) + { // if no description is specified, temporarily use plugin file, // until plugin can be queried, and desc replaced with info->name. safevoid_snprintf(desc, sizeof(desc), "<%s>", file); } - return(mTRUE); + + return mTRUE; } // Try to resolve a plugin's filename as a (possibly partial) path to an // actual filename on disk, to facilitate easier console load-command -// arguments. Uses resolve_dirs, resolve_prefix, and resolve_suffix below. +// arguments. Uses resolve_dirs, resolve_prefix, and resolve_suffix below. // Example paths that it tries: // filename // Gamedir/filename.dll, Gamedir/filename.so @@ -233,71 +250,84 @@ mBOOL DLLINTERNAL MPlugin::check_input(void) { // meta_errno values: // - ME_NOTFOUND couldn't find a matching file for the partial name // - errno's from check_input() -mBOOL DLLINTERNAL MPlugin::resolve(void) { +mBOOL MPlugin::resolve() +{ char *found; char *cp; int len; - if(!check_input()) { + if (!check_input()) { // details logged, meta_errno set in check_input() - return(mFALSE); + return mFALSE; } - if(is_absolute_path(filename)) - found=resolve_prefix(filename); - else - found=resolve_dirs(filename); - if(!found) { + if (is_absolute_path(filename)) + found = resolve_prefix(filename); + else + found = resolve_dirs(filename); + + if (!found) + { META_DEBUG(2, ("Couldn't resolve '%s' to file", filename)); RETURN_ERRNO(mFALSE, ME_NOTFOUND); } + META_DEBUG(2, ("Resolved '%s' to file '%s'", filename, found)); + // store pathname: the resolved path (should be absolute) - STRNCPY(pathname, found, sizeof(pathname)); + Q_strncpy(pathname, found, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + // store file: the name of the file (without dir) - cp=Q_strrchr(pathname, '/'); - if(cp) + cp = Q_strrchr(pathname, '/'); + if (cp) file=cp+1; else file=pathname; // store pathname: the gamedir relative path, or an absolute path len=Q_strlen(GameDLL.gamedir); - if(strncasecmp(pathname, GameDLL.gamedir, len) == 0) - STRNCPY(filename, pathname+len+1, sizeof(filename)); + if (strncasecmp(pathname, GameDLL.gamedir, len) == 0) + { + Q_strncpy(filename, pathname + len + 1, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } else - STRNCPY(filename, pathname, sizeof(filename)); + { + Q_strncpy(filename, pathname, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } - return(mTRUE); + return mTRUE; } -// For the given path, tries to find file in several possible +// For the given path, tries to find file in several possible // directories. // Try: // GAMEDIR/filename // GAMEDIR/dlls/filename // meta_errno values: // - none -char * DLLINTERNAL MPlugin::resolve_dirs(const char *path) { +char *MPlugin::resolve_dirs(const char *path) { struct stat st; static char buf[PATH_MAX]; char *found; safevoid_snprintf(buf, sizeof(buf), "%s/%s", GameDLL.gamedir, path); // try this path - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; // try other file prefixes in this path - if((found=resolve_prefix(buf))) - return(found); + if ((found=resolve_prefix(buf))) + return found; safevoid_snprintf(buf, sizeof(buf), "%s/dlls/%s", GameDLL.gamedir, path); // try this path - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; // try other file prefixes for this path - if((found=resolve_prefix(buf))) - return(found); + if ((found=resolve_prefix(buf))) + return found; - return(NULL); + return NULL; } // For the given path, tries several possible filename prefixes. @@ -306,7 +336,7 @@ char * DLLINTERNAL MPlugin::resolve_dirs(const char *path) { // dir/file // meta_errno values: // - none -char * DLLINTERNAL MPlugin::resolve_prefix(const char *path) { +char *MPlugin::resolve_prefix(const char *path) { struct stat st; char *cp, *fname; char dname[PATH_MAX]; @@ -315,29 +345,33 @@ char * DLLINTERNAL MPlugin::resolve_prefix(const char *path) { // try "mm_" prefix FIRST. // split into dirname and filename - STRNCPY(dname, path, sizeof(dname)); - cp=Q_strrchr(dname, '/'); - if(cp) { - *cp='\0'; - fname=cp+1; + Q_strncpy(dname, path, sizeof(dname) - 1); + dname[sizeof(dname) - 1] = '\0'; + + cp = Q_strrchr(dname, '/'); + if (cp) + { + *cp = '\0'; + fname = cp + 1; safevoid_snprintf(buf, sizeof(buf), "%s/mm_%s", dname, fname); } - else { + else + { // no directory in given path safevoid_snprintf(buf, sizeof(buf), "mm_%s", path); } // try this path - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; // try other suffixes for this path - if((found=resolve_suffix(buf))) - return(found); + if ((found=resolve_suffix(buf))) + return found; // try other suffixes for the original path - if((found=resolve_suffix(path))) - return(found); + if ((found=resolve_suffix(path))) + return found; - return(NULL); + return NULL; } // For the given path, tries several different filename suffixes. @@ -349,27 +383,27 @@ char * DLLINTERNAL MPlugin::resolve_prefix(const char *path) { // path_i386.so, path_i486.so, etc (if linux) // meta_errno values: // - none -char * DLLINTERNAL MPlugin::resolve_suffix(const char *path) { +char *MPlugin::resolve_suffix(const char *path) { struct stat st; static char buf[PATH_MAX]; static char tmpbuf[PATH_MAX]; char *found; // Hmm, recursion. - if(!Q_strstr(path, "_mm")) { + if (!Q_strstr(path, "_mm")) { safevoid_snprintf(buf, sizeof(buf), "%s_mm", path); Q_memcpy(tmpbuf,buf,sizeof(tmpbuf)); found=resolve_suffix(tmpbuf); - if(found) - return(found); + if (found) + return found; } - - if(!Q_strstr(path, "_MM")) { + + if (!Q_strstr(path, "_MM")) { safevoid_snprintf(buf, sizeof(buf), "%s_MM", path); Q_memcpy(tmpbuf,buf,sizeof(tmpbuf)); found=resolve_suffix(tmpbuf); - if(found) - return(found); + if (found) + return found; } #ifdef _WIN32 @@ -379,44 +413,32 @@ char * DLLINTERNAL MPlugin::resolve_suffix(const char *path) { #else #error "OS unrecognized" #endif /* _WIN32 */ - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; -#ifdef linux -#ifdef __x86_64__ - safevoid_snprintf(buf, sizeof(buf), "%s_amd64.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); - safevoid_snprintf(buf, sizeof(buf), "%s_x86_64.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); - safevoid_snprintf(buf, sizeof(buf), "%s_x86-64.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); -#else +#ifndef _WIN32 safevoid_snprintf(buf, sizeof(buf), "%s_i386.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; safevoid_snprintf(buf, sizeof(buf), "%s_i486.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; safevoid_snprintf(buf, sizeof(buf), "%s_i586.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; safevoid_snprintf(buf, sizeof(buf), "%s_i686.so", path); - if(stat(buf, &st) == 0 && S_ISREG(st.st_mode)) - return(buf); -#endif /* !__x86_64__ */ -#endif /* linux */ + if (stat(buf, &st) == 0 && S_ISREG(st.st_mode)) + return buf; +#endif - return(NULL); + return NULL; } // Check if a passed string starts with a known platform postfix. // It does not check beyond the period in order to work for both // Linux and Win32. -mBOOL DLLINTERNAL MPlugin::is_platform_postfix(const char *pf) { +mBOOL MPlugin::is_platform_postfix(const char *pf) { typedef struct { const char * postfix; size_t len; } postfix_t; static const postfix_t postfixes[] = { {"_i386.", 6}, @@ -428,16 +450,16 @@ mBOOL DLLINTERNAL MPlugin::is_platform_postfix(const char *pf) { {"_x86-64.", 8}, {0,0}, }; - - if(!pf) - return(mFALSE); - - for(const postfix_t * plist = postfixes; plist->postfix; plist++) { - if(!mm_strncmp(pf, plist->postfix, plist->len)) - return(mTRUE); + + if (!pf) + return mFALSE; + + for (const postfix_t * plist = postfixes; plist->postfix; plist++) { + if (!Q_strncmp(pf, plist->postfix, plist->len)) + return mTRUE; } - - return(mFALSE); + + return mFALSE; } @@ -448,47 +470,46 @@ mBOOL DLLINTERNAL MPlugin::is_platform_postfix(const char *pf) { // 2b. the description is the same, or // 3. a significant part of the filename is the same. // A significant part of a plugin name is currently defined to: -// the part up to a known platform postfix as determined by +// the part up to a known platform postfix as determined by // the is_platform_postfix() function (see above), or // the part up to the last dot, if one exists. // meta_errno values: // - none -mBOOL DLLINTERNAL MPlugin::platform_match(MPlugin* other) { +mBOOL MPlugin::platform_match(MPlugin* other) { char *end, *other_end; int prefixlen; - if(status < PL_VALID || other->status < PL_VALID) - return(mFALSE); + if (status < PL_VALID || other->status < PL_VALID) + return mFALSE; + + if (!Q_strcmp(file, other->file)) + return mTRUE; + + if (status >= PL_OPENED && other->status >= PL_OPENED && !Q_strcmp(info->logtag, other->info->logtag)) + return mTRUE; + + if (*desc != '\0' && !Q_stricmp(desc,other->desc)) + return mTRUE; - if(mm_strcmp(file, other->file) == 0) - return(mTRUE); - - if(status >= PL_OPENED && other->status >= PL_OPENED && - mm_strcmp(info->logtag, other->info->logtag) == 0) - return(mTRUE); - - if(*desc != '\0' && strcasecmp(desc,other->desc) == 0) - return(mTRUE); - end=Q_strrchr(file, '_'); - if(end == NULL || !is_platform_postfix(end)) + if (end == NULL || !is_platform_postfix(end)) end=Q_strrchr(file, '.'); - + other_end=Q_strrchr(other->file, '_'); - if(other_end == NULL || !is_platform_postfix(other_end)) + if (other_end == NULL || !is_platform_postfix(other_end)) other_end=Q_strrchr(other->file, '.'); - - if(end == NULL || other_end == NULL) - return(mFALSE); + + if (end == NULL || other_end == NULL) + return mFALSE; prefixlen=end-file; - if((other_end-other->file) != prefixlen) - return(mFALSE); - - if(mm_strncmp(file,other->file, prefixlen) == 0) - return(mTRUE); - - return(mFALSE); + if ((other_end-other->file) != prefixlen) + return mFALSE; + + if (!Q_strncmp(file,other->file, prefixlen)) + return mTRUE; + + return mFALSE; } // Load a plugin; query, check allowed time, attach. @@ -501,28 +522,28 @@ mBOOL DLLINTERNAL MPlugin::platform_match(MPlugin* other) { // - errno's from query() // - errno's from attach() // - errno's from check_input() -mBOOL DLLINTERNAL MPlugin::load(PLUG_LOADTIME now) { - if(!check_input()) { +mBOOL MPlugin::load(PLUG_LOADTIME now) { + if (!check_input()) { // details logged, meta_errno set in check_input() RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(status >= PL_RUNNING) { - META_WARNING("dll: Not loading plugin '%s'; already loaded (status=%s)", + if (status >= PL_RUNNING) { + META_WARNING("dll: Not loading plugin '%s'; already loaded (status=%s)", desc, str_status()); RETURN_ERRNO(mFALSE, ME_ALREADY); } - if(action != PA_LOAD && action != PA_ATTACH && action != PA_RELOAD) { + if (action != PA_LOAD && action != PA_ATTACH && action != PA_RELOAD) { META_WARNING("dll: Not loading plugin '%s'; not marked for load (action=%s)", desc, str_action()); RETURN_ERRNO(mFALSE, ME_BADREQ); } - if(status <= PL_OPENED) { + if (status <= PL_OPENED) { // query plugin; open file and get info about it - if(!query()) { + if (!query()) { META_WARNING("dll: Skipping plugin '%s'; couldn't query", desc); - if(meta_errno != ME_DLOPEN) { - if(DLCLOSE(handle) != 0) { - META_WARNING("dll: Couldn't close plugin file '%s': %s", + if (meta_errno != ME_DLOPEN) { + if (DLCLOSE(handle) != 0) { + META_WARNING("dll: Couldn't close plugin file '%s': %s", file, DLERROR()); } else @@ -531,21 +552,21 @@ mBOOL DLLINTERNAL MPlugin::load(PLUG_LOADTIME now) { status=PL_BADFILE; info=NULL; // prevent crash // meta_errno should be already set in query() - return(mFALSE); + return mFALSE; } status=PL_OPENED; } // are we allowed to attach this plugin at this time? - if(info->loadable < now) { - if(info->loadable > PT_STARTUP) { + if (info->loadable < now) { + if (info->loadable > PT_STARTUP) { // will try to attach again at next opportunity - META_DEBUG(2, ("dll: Delaying load plugin '%s'; can't attach now: allowed=%s; now=%s", + META_DEBUG(2, ("dll: Delaying load plugin '%s'; can't attach now: allowed=%s; now=%s", desc, str_loadable(), str_loadtime(now, SL_SIMPLE))); RETURN_ERRNO(mFALSE, ME_DELAYED); } else { - META_DEBUG(2, ("dll: Failed load plugin '%s'; can't attach now: allowed=%s; now=%s", + META_DEBUG(2, ("dll: Failed load plugin '%s'; can't attach now: allowed=%s; now=%s", desc, str_loadable(), str_loadtime(now, SL_SIMPLE))); // don't try to attach again later action=PA_NONE; @@ -554,7 +575,7 @@ mBOOL DLLINTERNAL MPlugin::load(PLUG_LOADTIME now) { } // attach plugin; get function tables - if(attach(now) != mTRUE) { + if (attach(now) != mTRUE) { META_WARNING("dll: Failed to attach plugin '%s'", desc); // Note we don't dlclose() here, since we're returning PL_FAILED, // which implies that it's been dlopened and queried successfully. @@ -563,17 +584,17 @@ mBOOL DLLINTERNAL MPlugin::load(PLUG_LOADTIME now) { // (segfault) after dlclosed. status=PL_FAILED; // meta_errno should be already set in attach() - return(mFALSE); + return mFALSE; } - + status=PL_RUNNING; action=PA_NONE; - + // If not loading at server startup, then need to call plugin's // GameInit, since we've passed that. - if(now != PT_STARTUP) { + if (now != PT_STARTUP) { FN_GAMEINIT pfn_gameinit=NULL; - if(tables.dllapi && (pfn_gameinit=tables.dllapi->pfnGameInit)) + if (tables.dllapi && (pfn_gameinit=tables.dllapi->pfnGameInit)) pfn_gameinit(); } // If loading during map, then I'd like to call plugin's @@ -582,23 +603,24 @@ mBOOL DLLINTERNAL MPlugin::load(PLUG_LOADTIME now) { // moment that plugins that are loadable during a map can't need to // hook ServerActivate. - META_LOG("dll: Loaded plugin '%s': %s v%s %s, %s", desc, info->name, + META_LOG("dll: Loaded plugin '%s': %s v%s %s, %s", desc, info->name, info->version, info->date, info->author); - return(mTRUE); + return mTRUE; } // Query a plugin: // - dlopen() the file, store the handle // - dlsym() and call: // Meta_Init (if present) - tell dll it'll be used as a metamod plugin -// GiveFnptrsToDll - give engine function ptrs +// GiveFnptrsToDll - give engine function ptrs // Meta_Query - say "hi" and get info about plugin // meta_errno values: // - ME_DLOPEN dlopen/loadlibrary failed; see dlerror() for details // - ME_DLMISSING couldn't find a query() or giveFuncs() in plugin // - ME_DLERROR plugin query() returned error // - ME_NULLDATA info struct from query() was null -mBOOL DLLINTERNAL MPlugin::query(void) { +mBOOL MPlugin::query() +{ int plugin_pext_version; META_GIVE_PEXT_FUNCTIONS_FN pfn_give_pext_funcs; META_INIT_FN pfn_init; @@ -606,7 +628,7 @@ mBOOL DLLINTERNAL MPlugin::query(void) { META_QUERY_FN pfn_query; // open the plugin DLL - if(!(handle=DLOPEN(pathname))) { + if (!(handle=DLOPEN(pathname))) { META_WARNING("dll: Failed query plugin '%s'; Couldn't open file '%s': %s", desc, pathname, DLERROR()); RETURN_ERRNO(mFALSE, ME_DLOPEN); @@ -618,12 +640,12 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // startup in GiveFnptrsToDll, and trying to load them as metamod // plugins creates all sorts of crashes. So, we do a trivial check // first to see if the DLL looks like a metamod plugin before - // proceeding with the normal order. Note that we still have to call - // GiveFnptrsToDll before Meta_Query, because the latter typically uses - // engine functions like AlertMessage, which have to be passed along via + // proceeding with the normal order. Note that we still have to call + // GiveFnptrsToDll before Meta_Query, because the latter typically uses + // engine functions like AlertMessage, which have to be passed along via // GiveFnptrsToDll. pfn_query = (META_QUERY_FN) DLSYM(handle, "Meta_Query"); - if(!pfn_query) { + if (!pfn_query) { META_WARNING("dll: Failed query plugin '%s'; Couldn't find Meta_Query(): %s", desc, DLERROR()); // caller will dlclose() RETURN_ERRNO(mFALSE, ME_DLMISSING); @@ -631,7 +653,7 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // Call Meta_Init, if present. This is an optional plugin routine to // allow plugin to do any special initializing or other processing - // prior to the standard query/attach procedure. + // prior to the standard query/attach procedure. // // In particular, this should allow for DLL's that can operate as both // a standalone dll AND a metamod plugin. This routine has to be @@ -644,7 +666,7 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // plugin can NOT use any Engine functions, as they haven't been // provided yet (done next, in GiveFnptrsToDll). pfn_init = (META_INIT_FN) DLSYM(handle, "Meta_Init"); - if(pfn_init) { + if (pfn_init) { pfn_init(); META_DEBUG(6, ("dll: Plugin '%s': Called Meta_Init()", desc)); } @@ -652,9 +674,9 @@ mBOOL DLLINTERNAL MPlugin::query(void) { META_DEBUG(5, ("dll: no Meta_Init present in plugin '%s'", desc)); // don't return; not an error } - + // pass on engine function table and globals to plugin - if(!(pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(handle, "GiveFnptrsToDll"))) { + if (!(pfn_give_engfuncs = (GIVE_ENGINE_FUNCTIONS_FN) DLSYM(handle, "GiveFnptrsToDll"))) { // META_WARNING("dll: Couldn't find GiveFnptrsToDll() in plugin '%s': %s", desc, DLERROR()); META_WARNING("dll: Failed query plugin '%s'; Couldn't find GiveFnptrsToDll(): %s", desc, DLERROR()); // caller will dlclose() @@ -671,13 +693,13 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // same reason. Q_memcpy(&mutil_funcs, &MetaUtilFunctions, sizeof(mutil_funcs)); - if(pfn_query(META_INTERFACE_VERSION, &info, &mutil_funcs) != TRUE) { - META_WARNING("dll: Failed query plugin '%s'; Meta_Query returned error", + if (pfn_query(META_INTERFACE_VERSION, &info, &mutil_funcs) != TRUE) { + META_WARNING("dll: Failed query plugin '%s'; Meta_Query returned error", desc); meta_errno=ME_DLERROR; } else { - META_DEBUG(6, ("dll: Plugin '%s': Called Meta_Query() successfully", + META_DEBUG(6, ("dll: Plugin '%s': Called Meta_Query() successfully", desc)); } @@ -690,77 +712,80 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // // Note, this check is done regardless of whether meta_query returns an // error. - if(info && !FStrEq(info->ifvers, META_INTERFACE_VERSION)) { + if (info && !FStrEq(info->ifvers, META_INTERFACE_VERSION)) { int mmajor=0, mminor=0, pmajor=0, pminor=0; META_DEBUG(3, ("dll: Note: Plugin '%s' interface version didn't match; expected %s, found %s", desc, META_INTERFACE_VERSION, info->ifvers)); sscanf(META_INTERFACE_VERSION, "%d:%d", &mmajor, &mminor); sscanf(info->ifvers, "%d:%d", &pmajor, &pminor); - // If plugin has later interface version, it's incompatible + // If plugin has later interface version, it's incompatible // (update metamod). - if(pmajor > mmajor || (pmajor==mmajor && pminor > mminor)) { + if (pmajor > mmajor || (pmajor==mmajor && pminor > mminor)) { META_WARNING("dll: Plugin '%s' requires a newer version of Metamod (Metamod needs at least interface %s not the current %s)", desc, info->ifvers, META_INTERFACE_VERSION); meta_errno=ME_IFVERSION; } // If plugin has older major interface version, it's incompatible // (update plugin). - else if(pmajor < mmajor) { + else if (pmajor < mmajor) { META_WARNING("dll: Plugin '%s' is out of date and incompatible with this version of Metamod; please find a newer version of the plugin (plugin needs at least interface %s not the current %s)", desc, META_INTERFACE_VERSION, info->ifvers); meta_errno=ME_IFVERSION; } // Plugin has identical major, with older minor. This is supposed to be // backwards compatible, so we warn, but we still accept it. - else if(pmajor==mmajor && pminor < mminor) + else if (pmajor==mmajor && pminor < mminor) META_LOG("dll: Note: plugin '%s' is using an older interface version (%s), not the latest interface version (%s); there might be an updated version of the plugin", desc, info->ifvers, META_INTERFACE_VERSION); else - META_LOG("dll: Plugin '%s': unexpected version comparision; metavers=%s, mmajor=%d, mminor=%d; plugvers=%s, pmajor=%d, pminor=%d", + META_LOG("dll: Plugin '%s': unexpected version comparision; metavers=%s, mmajor=%d, mminor=%d; plugvers=%s, pmajor=%d, pminor=%d", desc, META_INTERFACE_VERSION, mmajor, mminor, info->ifvers, pmajor, pminor); } - - if(meta_errno == ME_IFVERSION) { + + if (meta_errno == ME_IFVERSION) { META_WARNING("dll: Rejected plugin '%s' due to interface version incompatibility (mm=%s, pl=%s)", desc, META_INTERFACE_VERSION, info->ifvers); // meta_errno is set already above // caller will dlclose() - return(mFALSE); + return mFALSE; } - else if(meta_errno != ME_NOERROR) { + else if (meta_errno != ME_NOERROR) { // some other error, already logged - return(mFALSE); + return mFALSE; } - - if(!info) { + + if (!info) { META_WARNING("dll: Failed query plugin '%s'; Empty info structure", desc); // caller will dlclose() RETURN_ERRNO(mFALSE, ME_NULLRESULT); } // Replace temporary desc with plugin's internal name. - if(desc[0] == '<') - STRNCPY(desc, info->name, sizeof(desc)); - + if (desc[0] == '<') + { + Q_strncpy(desc, info->name, sizeof(desc) - 1); + desc[sizeof(desc) - 1] = '\0'; + } + // - // Give plugin the p-series extension function table. - // Check for version differences! + // Give plugin the p-series extension function table. + // Check for version differences! // - if(NULL!=(pfn_give_pext_funcs=(META_GIVE_PEXT_FUNCTIONS_FN) DLSYM(handle, "Meta_PExtGiveFnptrs"))) { + if (NULL!=(pfn_give_pext_funcs=(META_GIVE_PEXT_FUNCTIONS_FN) DLSYM(handle, "Meta_PExtGiveFnptrs"))) { plugin_pext_version = (*pfn_give_pext_funcs)(META_PEXT_VERSION, (pextension_funcs_t*)(&(mutil_funcs.pfnLoadPlugin))); - + //if plugin is newer, we got incompatibility problem! - if(plugin_pext_version > META_PEXT_VERSION) { + if (plugin_pext_version > META_PEXT_VERSION) { META_WARNING("dll: Plugin '%s' requires a newer version of Metamod-P (extension interface needs to be at least %d not the current %d)", desc, plugin_pext_version, META_PEXT_VERSION); } } - + META_DEBUG(6, ("dll: Plugin '%s': Query successful", desc)); - - return(mTRUE); + + return mTRUE; } // Attach a plugin: // - dlsym() and call: // Meta_Attach - get table of api tables, give meta_globals -// - if provided by plugin, call various "Get" function pointers, +// - if provided by plugin, call various "Get" function pointers, // and store resulting function tables: // GetEntityAPI (std) // GetEntityAPI2 (std sdk2) @@ -776,7 +801,7 @@ mBOOL DLLINTERNAL MPlugin::query(void) { // - ME_DLMISSING couldn't find meta_attach() in plugin // - ME_DLERROR plugin attach() returned error // - ME_NOMEM failed malloc -mBOOL DLLINTERNAL MPlugin::attach(PLUG_LOADTIME now) { +mBOOL MPlugin::attach(PLUG_LOADTIME now) { int ret; int iface_vers; @@ -785,29 +810,29 @@ mBOOL DLLINTERNAL MPlugin::attach(PLUG_LOADTIME now) { // Make copy of gameDLL's function tables for each plugin, so we don't // risk the plugins screwing with the tables everyone uses. - if(!gamedll_funcs.dllapi_table) { + if (!gamedll_funcs.dllapi_table) { gamedll_funcs.dllapi_table = (DLL_FUNCTIONS *) calloc(1, sizeof(DLL_FUNCTIONS)); - if(!gamedll_funcs.dllapi_table) { + if (!gamedll_funcs.dllapi_table) { META_WARNING("dll: Failed attach plugin '%s': Failed malloc() for dllapi_table"); RETURN_ERRNO(mFALSE, ME_NOMEM); } - if(GameDLL.funcs.dllapi_table) + if (GameDLL.funcs.dllapi_table) Q_memcpy(gamedll_funcs.dllapi_table, GameDLL.funcs.dllapi_table, sizeof(DLL_FUNCTIONS)); else Q_memset(gamedll_funcs.dllapi_table, 0, sizeof(DLL_FUNCTIONS)); } - if(!gamedll_funcs.newapi_table) { + if (!gamedll_funcs.newapi_table) { gamedll_funcs.newapi_table = (NEW_DLL_FUNCTIONS *) calloc(1, sizeof(NEW_DLL_FUNCTIONS)); - if(!gamedll_funcs.newapi_table) { + if (!gamedll_funcs.newapi_table) { META_WARNING("dll: Failed attach plugin '%s': Failed malloc() for newapi_table"); RETURN_ERRNO(mFALSE, ME_NOMEM); } - if(GameDLL.funcs.newapi_table) + if (GameDLL.funcs.newapi_table) Q_memcpy(gamedll_funcs.newapi_table, GameDLL.funcs.newapi_table, sizeof(NEW_DLL_FUNCTIONS)); else Q_memset(gamedll_funcs.newapi_table, 0, sizeof(NEW_DLL_FUNCTIONS)); } - if(!(pfn_attach = (META_ATTACH_FN) DLSYM(handle, "Meta_Attach"))) { + if (!(pfn_attach = (META_ATTACH_FN) DLSYM(handle, "Meta_Attach"))) { META_WARNING("dll: Failed attach plugin '%s': Couldn't find Meta_Attach(): %s", desc, DLERROR()); // caller will dlclose() RETURN_ERRNO(mFALSE, ME_DLMISSING); @@ -817,7 +842,7 @@ mBOOL DLLINTERNAL MPlugin::attach(PLUG_LOADTIME now) { // get table of function tables, // give public meta globals ret=pfn_attach(now, &meta_table, &PublicMetaGlobals, &gamedll_funcs); - if(ret != TRUE) { + if (ret != TRUE) { META_WARNING("dll: Failed attach plugin '%s': Error from Meta_Attach(): %d", desc, ret); // caller will dlclose() RETURN_ERRNO(mFALSE, ME_DLERROR); @@ -827,24 +852,24 @@ mBOOL DLLINTERNAL MPlugin::attach(PLUG_LOADTIME now) { // Rather than duplicate code, we use another ugly macro. Again, // a function isn't an option since we have varying types. #define GET_FUNC_TABLE_FROM_PLUGIN(pfnGetFuncs, STR_GetFuncs, struct_field, API_TYPE, TABLE_TYPE, TABLE_SIZE, vers_pass, vers_int, vers_want) \ - if(meta_table.pfnGetFuncs) { \ - if(!struct_field) { \ + if (meta_table.pfnGetFuncs) { \ + if (!struct_field) { \ struct_field = (TABLE_TYPE*)calloc(1, TABLE_SIZE); \ } else { \ Q_memset(struct_field, 0, TABLE_SIZE); \ } \ - if(meta_table.pfnGetFuncs(struct_field, vers_pass)) { \ + if (meta_table.pfnGetFuncs(struct_field, vers_pass)) { \ META_DEBUG(3, ("dll: Plugin '%s': Found %s", desc, STR_GetFuncs)); \ } \ else { \ META_WARNING("dll: Failure calling %s in plugin '%s'", STR_GetFuncs, desc); \ - if(vers_int != vers_want) \ + if (vers_int != vers_want) \ META_WARNING("dll: Interface version didn't match; expected %d, found %d", vers_want, vers_int); \ } \ } \ else { \ META_DEBUG(5, ("dll: Plugin '%s': No %s", desc, STR_GetFuncs)); \ - if(struct_field) \ + if (struct_field) \ free(struct_field); \ struct_field=NULL; \ } @@ -852,111 +877,111 @@ mBOOL DLLINTERNAL MPlugin::attach(PLUG_LOADTIME now) { // Look for API-NEW interface in plugin. We do this before API2/API, because // that's what the engine appears to do.. iface_vers=NEW_DLL_FUNCTIONS_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetNewDLLFunctions, - "GetNewDLLFunctions", tables.newapi, + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetNewDLLFunctions, + "GetNewDLLFunctions", tables.newapi, NEW_DLL_FUNCTIONS_FN, NEW_DLL_FUNCTIONS, sizeof(NEW_DLL_FUNCTIONS), &iface_vers, iface_vers, NEW_DLL_FUNCTIONS_VERSION); iface_vers=NEW_DLL_FUNCTIONS_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetNewDLLFunctions_Post, - "GetNewDLLFunctions_Post", post_tables.newapi, + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetNewDLLFunctions_Post, + "GetNewDLLFunctions_Post", post_tables.newapi, NEW_DLL_FUNCTIONS_FN, NEW_DLL_FUNCTIONS, sizeof(NEW_DLL_FUNCTIONS), &iface_vers, iface_vers, NEW_DLL_FUNCTIONS_VERSION); // Look for API2 interface in plugin; preferred over API-1. iface_vers=INTERFACE_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI2, - "GetEntityAPI2", tables.dllapi, + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI2, + "GetEntityAPI2", tables.dllapi, APIFUNCTION2, DLL_FUNCTIONS, sizeof(DLL_FUNCTIONS), &iface_vers, iface_vers, INTERFACE_VERSION); iface_vers=INTERFACE_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI2_Post, - "GetEntityAPI2_Post", post_tables.dllapi, + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI2_Post, + "GetEntityAPI2_Post", post_tables.dllapi, APIFUNCTION2, DLL_FUNCTIONS, sizeof(DLL_FUNCTIONS), &iface_vers, iface_vers, INTERFACE_VERSION); // Look for old-style API in plugin, if API2 interface wasn't found. - if(!tables.dllapi && !post_tables.dllapi) { - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI, - "GetEntityAPI", tables.dllapi, + if (!tables.dllapi && !post_tables.dllapi) { + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI, + "GetEntityAPI", tables.dllapi, APIFUNCTION, DLL_FUNCTIONS, sizeof(DLL_FUNCTIONS), INTERFACE_VERSION, INTERFACE_VERSION, INTERFACE_VERSION); - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI_Post, - "GetEntityAPI_Post", post_tables.dllapi, + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEntityAPI_Post, + "GetEntityAPI_Post", post_tables.dllapi, APIFUNCTION, DLL_FUNCTIONS, sizeof(DLL_FUNCTIONS), INTERFACE_VERSION, INTERFACE_VERSION, INTERFACE_VERSION); } // Look for Engine interface. iface_vers=ENGINE_INTERFACE_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEngineFunctions, - "GetEngineFunctions", tables.engine, - GET_ENGINE_FUNCTIONS_FN, enginefuncs_t, (sizeof(enginefuncs_t) - sizeof(((enginefuncs_t*)0)->extra_functions)), + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEngineFunctions, + "GetEngineFunctions", tables.engine, + GET_ENGINE_FUNCTIONS_FN, enginefuncs_t, sizeof(enginefuncs_t), &iface_vers, iface_vers, ENGINE_INTERFACE_VERSION); iface_vers=ENGINE_INTERFACE_VERSION; - GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEngineFunctions_Post, - "GetEngineFunctions_Post", post_tables.engine, - GET_ENGINE_FUNCTIONS_FN, enginefuncs_t, (sizeof(enginefuncs_t) - sizeof(((enginefuncs_t*)0)->extra_functions)), + GET_FUNC_TABLE_FROM_PLUGIN(pfnGetEngineFunctions_Post, + "GetEngineFunctions_Post", post_tables.engine, + GET_ENGINE_FUNCTIONS_FN, enginefuncs_t, sizeof(enginefuncs_t), &iface_vers, iface_vers, ENGINE_INTERFACE_VERSION); - if(!tables.dllapi && !post_tables.dllapi + if (!tables.dllapi && !post_tables.dllapi && !tables.newapi && !post_tables.newapi && !tables.engine && !post_tables.engine) { META_LOG("dll: Plugin '%s' isn't catching _any_ functions ??", desc); } - + time_loaded=time(NULL); - return(mTRUE); + return mTRUE; } // Unload a plugin from plugin request // meta_errno values: // - errno's from unload() -mBOOL DLLINTERNAL MPlugin::plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { +mBOOL MPlugin::plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { PLUG_ACTION old_action; MPlugin * pl_unloader; - + // try find unloader - if(!(pl_unloader=Plugins->find(plid))) { + if (!(pl_unloader=Plugins->find(plid))) { META_WARNING("dll: Not unloading plugin '%s'; plugin that requested unload is not found.", desc); RETURN_ERRNO(mFALSE, ME_BADREQ); - } + } // self check. Do not allow plugin to unload itself! - else if(pl_unloader->index == index) { + else if (pl_unloader->index == index) { META_WARNING("dll: Not unloading plugin '%s'; Plugin tried to unload itself.", desc); RETURN_ERRNO(mFALSE, ME_UNLOAD_SELF); } // safe check. Do not allow active unloader to be unloaded! - else if(is_unloader) { + else if (is_unloader) { META_WARNING("dll: Not unloading plugin '%s'; Plugin is unloading plugin that tried to unload it.", desc); RETURN_ERRNO(mFALSE, ME_UNLOAD_UNLOADER); } else { unloader_index=pl_unloader->index; } - + // block unloader from being unloaded by other plugin pl_unloader->is_unloader = mTRUE; - + // try unload old_action=action; action=PA_UNLOAD; - if(unload(now, reason, (reason==PNL_CMD_FORCED) ? PNL_PLG_FORCED : PNL_PLUGIN)) { + if (unload(now, reason, (reason==PNL_CMD_FORCED) ? PNL_PLG_FORCED : PNL_PLUGIN)) { META_DEBUG(1,("Unloaded plugin '%s'", desc)); pl_unloader->is_unloader = mFALSE; - return(mTRUE); + return mTRUE; } - + pl_unloader->is_unloader = mFALSE; - + // Cannot unload plugin now. Don't set delayed mode. - if(meta_errno==ME_DELAYED) { + if (meta_errno==ME_DELAYED) { action=old_action; meta_errno = ME_NOTALLOWED; META_DEBUG(2, ("dll: Failed unload plugin '%s'; can't detach now: allowed=%s; now=%s", desc, str_unloadable(), str_loadtime(PT_ANYTIME, SL_SIMPLE))); } - - return(mFALSE); + + return mFALSE; } // Unload a plugin. Check time, detach. @@ -967,30 +992,30 @@ mBOOL DLLINTERNAL MPlugin::plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLO // - ME_DELAYED unload request is delayed (till changelevel?) // - ME_NOTALLOWED plugin not unloadable after startup // - errno's from check_input() -mBOOL DLLINTERNAL MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason) { - if(!check_input()) { +mBOOL MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason) { + if (!check_input()) { // details logged, meta_errno set in check_input() RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - if(status < PL_RUNNING) { - if(reason != PNL_CMD_FORCED && reason != PNL_RELOAD) { + if (status < PL_RUNNING) { + if (reason != PNL_CMD_FORCED && reason != PNL_RELOAD) { META_WARNING("dll: Not unloading plugin '%s'; already unloaded (status=%s)", desc, str_status()); RETURN_ERRNO(mFALSE, ME_ALREADY); } } - if(action != PA_UNLOAD && action != PA_RELOAD) { + if (action != PA_UNLOAD && action != PA_RELOAD) { META_WARNING("dll: Not unloading plugin '%s'; not marked for unload (action=%s)", desc, str_action()); RETURN_ERRNO(mFALSE, ME_BADREQ); } // Are we allowed to detach this plugin at this time? // If forcing unload, we disregard when plugin wants to be unloaded. - if(info && info->unloadable < now) { - if(reason == PNL_CMD_FORCED) { + if (info && info->unloadable < now) { + if (reason == PNL_CMD_FORCED) { META_DEBUG(2, ("dll: Forced unload plugin '%s' overriding allowed times: allowed=%s; now=%s", desc, str_unloadable(), str_loadtime(now, SL_SIMPLE))); } else { - if(info->unloadable > PT_STARTUP) { + if (info->unloadable > PT_STARTUP) { META_DEBUG(2, ("dll: Delaying unload plugin '%s'; can't detach now: allowed=%s; now=%s", desc, str_unloadable(), str_loadtime(now, SL_SIMPLE))); // caller should give message to user // try to unload again at next opportunity @@ -1011,22 +1036,22 @@ mBOOL DLLINTERNAL MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL // indicates these two routines should match call for call. // detach plugin - if(!detach(now, reason)) { - if(reason == PNL_RELOAD) { + if (!detach(now, reason)) { + if (reason == PNL_RELOAD) { META_DEBUG(2, ("dll: Reload plugin '%s' overriding failed detach", desc)); } - else if(reason == PNL_CMD_FORCED) { + else if (reason == PNL_CMD_FORCED) { META_DEBUG(2, ("dll: Forced unload plugin '%s' overriding failed detach", desc)); } else { META_WARNING("dll: Failed to detach plugin '%s'; ", desc); // meta_errno should be already set in detach() - return(mFALSE); + return mFALSE; } } // successful detach, or forced unload - + // clear source_plugin_index for all plugins that this plugin has loaded Plugins->clear_source_plugin_index(index); @@ -1037,54 +1062,54 @@ mBOOL DLLINTERNAL MPlugin::unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL // Close the file. Note: after this, attempts to reference any memory // locations in the file will produce a segfault. - if(DLCLOSE(handle) != 0) { + if (DLCLOSE(handle) != 0) { // If DLL cannot be closed, OS is badly broken or we are giving invalid handle. // So we don't return here but instead remove plugin from our listings. META_WARNING("dll: Couldn't dlclose plugin file '%s': %s", file, DLERROR()); } handle=NULL; - if(action==PA_UNLOAD) { + if (action==PA_UNLOAD) { status=PL_EMPTY; clear(); } - else if(action==PA_RELOAD) { + else if (action==PA_RELOAD) { status=PL_VALID; action=PA_LOAD; clear(); } META_LOG("dll: Unloaded plugin '%s' for reason '%s'", desc, str_reason(reason, real_reason)); - return(mTRUE); + return mTRUE; } // Inform plugin we're going to unload it. // meta_errno values: -// - +// - // - ME_DLMISSING couldn't find meta_detach() in plugin // - ME_DLERROR plugin detach() returned error -mBOOL DLLINTERNAL MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { +mBOOL MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { int ret; META_DETACH_FN pfn_detach; // If we have no handle, i.e. no dll loaded, we return true because the // dll is obviously detached. We shouldn't call DLSYM() with a NULL // handle since this will DLSYM() ourself. - if(!handle) - return(mTRUE); + if (!handle) + return mTRUE; - if(!(pfn_detach = (META_DETACH_FN) DLSYM(handle, "Meta_Detach"))) { + if (!(pfn_detach = (META_DETACH_FN) DLSYM(handle, "Meta_Detach"))) { META_WARNING("dll: Error detach plugin '%s': Couldn't find Meta_Detach(): %s", desc, DLERROR()); // caller will dlclose() RETURN_ERRNO(mFALSE, ME_DLMISSING); } ret=pfn_detach(now, reason); - if(ret != TRUE) { + if (ret != TRUE) { META_WARNING("dll: Failed detach plugin '%s': Error from Meta_Detach(): %d", desc, ret); RETURN_ERRNO(mFALSE, ME_DLERROR); } META_DEBUG(6, ("dll: Plugin '%s': Called Meta_Detach() successfully", desc)); - return(mTRUE); + return mTRUE; } // Reload a plugin; unload and load again. @@ -1093,16 +1118,16 @@ mBOOL DLLINTERNAL MPlugin::detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { // - errno's from check_input() // - errno's from unload() // - errno's from load() -mBOOL DLLINTERNAL MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { - if(!check_input()) { +mBOOL MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { + if (!check_input()) { // details logged, meta_errno set in check_input() RETURN_ERRNO(mFALSE, ME_ARGUMENT); } - + // Are we allowed to load this plugin at this time? // If we cannot load the plugin after unloading it, we keep it. - if(info && info->loadable < now) { - if(info->loadable > PT_STARTUP) { + if (info && info->loadable < now) { + if (info->loadable > PT_STARTUP) { META_DEBUG(2, ("dll: Delaying reload plugin '%s'; would not be able to reattach now: allowed=%s; now=%s", desc, str_loadable(), str_loadtime(now, SL_SIMPLE))); // caller should give message to user // try to reload again at next opportunity @@ -1115,23 +1140,23 @@ mBOOL DLLINTERNAL MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { RETURN_ERRNO(mFALSE, ME_NOTALLOWED); } } - + //this is to fix unloading - if(status < PL_RUNNING) { + if (status < PL_RUNNING) { META_WARNING("dll: Plugin '%s' isn't running; Forcing unload plugin for reloading", desc); reason = PNL_RELOAD; } - if(!unload(now, reason, reason)) { + if (!unload(now, reason, reason)) { META_WARNING("dll: Failed to unload plugin '%s' for reloading", desc); // meta_errno should be set already in unload() - return(mFALSE); + return mFALSE; } - if(!load(now)) { + if (!load(now)) { META_WARNING("dll: Failed to reload plugin '%s' after unloading", desc); // meta_errno should be set already in load() - return(mFALSE); + return mFALSE; } - return(mTRUE); + return mTRUE; } // Pause a plugin; temporarily disabled for API routines. @@ -1139,18 +1164,19 @@ mBOOL DLLINTERNAL MPlugin::reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { // - ME_ALREADY this plugin already paused // - ME_BADREQ can't pause; not running // - ME_NOTALLOWED plugin doesn't want to be paused -mBOOL MPlugin::pause(void) { - if(status == PL_PAUSED) { +mBOOL MPlugin::pause() +{ + if (status == PL_PAUSED) { META_WARNING("Not pausing plugin '%s'; already paused", desc); RETURN_ERRNO(mFALSE, ME_ALREADY); } - if(status != PL_RUNNING) { + if (status != PL_RUNNING) { META_WARNING("Cannot pause plugin '%s'; not currently running (status=%s)", desc, str_status()); RETURN_ERRNO(mFALSE, ME_BADREQ); } // are we allowed to pause this plugin? - if(info->unloadable < PT_ANYPAUSE) { + if (info->unloadable < PT_ANYPAUSE) { META_WARNING("Cannot pause plugin '%s'; not allowed by plugin (allowed=%s)", desc, str_unloadable()); action=PA_NONE; RETURN_ERRNO(mFALSE, ME_NOTALLOWED); @@ -1158,20 +1184,21 @@ mBOOL MPlugin::pause(void) { status=PL_PAUSED; META_LOG("Paused plugin '%s'", desc); - return(mTRUE); + return mTRUE; } // Unpause a plugin. // meta_errno values: // - ME_BADREQ can't unpause; not paused -mBOOL DLLINTERNAL MPlugin::unpause(void) { - if(status != PL_PAUSED) { +mBOOL MPlugin::unpause() +{ + if (status != PL_PAUSED) { META_WARNING("Cannot unpause plugin '%s'; not currently paused (status=%s)", desc, str_status()); RETURN_ERRNO(mFALSE, ME_BADREQ); } status=PL_RUNNING; META_LOG("Unpaused plugin '%s'", desc); - return(mTRUE); + return mTRUE; } // Retry pending action, presumably from a previous failure. @@ -1180,39 +1207,41 @@ mBOOL DLLINTERNAL MPlugin::unpause(void) { // - errno's from load() // - errno's from unload() // - errno's from reload() -mBOOL DLLINTERNAL MPlugin::retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { - if(action==PA_LOAD) - return(load(now)); - else if(action==PA_ATTACH) - return(load(now)); - else if(action==PA_UNLOAD) - return(unload(now, reason, reason)); - else if(action==PA_RELOAD) - return(reload(now, reason)); - else { +mBOOL MPlugin::retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) +{ + switch (action) + { + case PA_LOAD: return load(now); + case PA_ATTACH: return load(now); + case PA_UNLOAD: return unload(now, reason, reason); + case PA_RELOAD: return reload(now, reason); + default: + { META_WARNING("No pending action to retry for plugin '%s'; (status=%s, action=%s)", desc, str_status(), str_action()); RETURN_ERRNO(mFALSE, ME_BADREQ); } + } } // -void DLLINTERNAL MPlugin::free_api_pointers(void) { - if(gamedll_funcs.dllapi_table) +void MPlugin::free_api_pointers() +{ + if (gamedll_funcs.dllapi_table) free(gamedll_funcs.dllapi_table); - if(gamedll_funcs.newapi_table) + if (gamedll_funcs.newapi_table) free(gamedll_funcs.newapi_table); - - if(tables.dllapi) + + if (tables.dllapi) free(tables.dllapi); - if(post_tables.dllapi) + if (post_tables.dllapi) free(post_tables.dllapi); - if(tables.newapi) + if (tables.newapi) free(tables.newapi); - if(post_tables.newapi) + if (post_tables.newapi) free(post_tables.newapi); - if(tables.engine) + if (tables.engine) free(tables.engine); - if(post_tables.engine) + if (post_tables.engine) free(post_tables.engine); } @@ -1221,15 +1250,16 @@ void DLLINTERNAL MPlugin::free_api_pointers(void) { // meta_errno values: // - ME_BADREQ not marked for clearing // - ME_DLERROR failed to dlclose -mBOOL DLLINTERNAL MPlugin::clear(void) { - if(status != PL_FAILED && status != PL_BADFILE +mBOOL MPlugin::clear() +{ + if (status != PL_FAILED && status != PL_BADFILE && status != PL_EMPTY && status != PL_OPENED) { META_WARNING("Cannot clear plugin '%s'; not marked as failed, empty, or open (status=%s)", desc, str_status()); RETURN_ERRNO(mFALSE, ME_BADREQ); } // If file is open, close the file. Note: after this, attempts to // reference any memory locations in the file will produce a segfault. - if(handle && DLCLOSE(handle) != 0) { + if (handle && DLCLOSE(handle) != 0) { META_WARNING("dll: Couldn't close plugin file '%s': %s", file, DLERROR()); status=PL_FAILED; RETURN_ERRNO(mFALSE, ME_DLERROR); @@ -1237,7 +1267,7 @@ mBOOL DLLINTERNAL MPlugin::clear(void) { handle=NULL; free_api_pointers(); - + status=PL_EMPTY; action=PA_NULL; handle=NULL; @@ -1247,14 +1277,15 @@ mBOOL DLLINTERNAL MPlugin::clear(void) { gamedll_funcs.newapi_table=NULL; Q_memset(&tables, 0, sizeof(tables)); Q_memset(&post_tables, 0, sizeof(post_tables)); - + Plugins->trim_list(); - - return(mTRUE); + + return mTRUE; } // List information about plugin to console. -void DLLINTERNAL MPlugin::show(void) { +void MPlugin::show() +{ char *cp, *tstr; int n, width; width=13; @@ -1277,19 +1308,19 @@ void DLLINTERNAL MPlugin::show(void) { META_CONS("%*s: %s", width, "ifvers", info ? info->ifvers : "(nil)"); // ctime() includes newline at EOL tstr=ctime(&time_loaded); - if((cp=Q_strchr(tstr, '\n'))) + if ((cp=Q_strchr(tstr, '\n'))) *cp='\0'; META_CONS("%*s: %s", width, "last loaded", tstr); // XXX show file time ? - if(tables.dllapi) { + if (tables.dllapi) { META_CONS("DLLAPI functions:"); SHOW_DEF_DLLAPI(tables.dllapi," ", ""); META_CONS("%d functions (dllapi)", n); } else META_CONS("No DLLAPI functions."); - if(post_tables.dllapi) { + if (post_tables.dllapi) { META_CONS("DLLAPI-Post functions:"); SHOW_DEF_DLLAPI(post_tables.dllapi, " ", "_Post"); META_CONS("%d functions (dllapi post)", n); @@ -1297,14 +1328,14 @@ void DLLINTERNAL MPlugin::show(void) { else META_CONS("No DLLAPI-Post functions."); - if(tables.newapi) { + if (tables.newapi) { META_CONS("NEWAPI functions:"); SHOW_DEF_NEWAPI(tables.newapi, " ", ""); META_CONS("%d functions (newapi)", n); } else META_CONS("No NEWAPI functions."); - if(post_tables.newapi) { + if (post_tables.newapi) { META_CONS("NEWAPI-Post functions:"); SHOW_DEF_NEWAPI(post_tables.newapi, " ", "_Post"); META_CONS("%d functions (newapi post)", n); @@ -1312,14 +1343,14 @@ void DLLINTERNAL MPlugin::show(void) { else META_CONS("No NEWAPI-Post functions."); - if(tables.engine) { + if (tables.engine) { META_CONS("Engine functions:"); SHOW_DEF_ENGINE(tables.engine, " ", ""); META_CONS("%d functions (engine)", n); } else META_CONS("No Engine functions."); - if(post_tables.engine) { + if (post_tables.engine) { META_CONS("Engine-Post functions:"); SHOW_DEF_ENGINE(post_tables.engine, " ", "_Post"); META_CONS("%d functions (engine post)", n); @@ -1328,8 +1359,8 @@ void DLLINTERNAL MPlugin::show(void) { META_CONS("No Engine-Post functions."); RegCmds->show(index); RegCvars->show(index); - - if(Plugins->found_child_plugins(index)) + + if (Plugins->found_child_plugins(index)) Plugins->show(index); else META_CONS("No child plugins."); @@ -1340,17 +1371,18 @@ void DLLINTERNAL MPlugin::show(void) { // meta_errno values: // - ME_NOFILE couldn't find file // - ME_NOERROR no error; false indicates file not newer -mBOOL DLLINTERNAL MPlugin::newer_file(void) { +mBOOL MPlugin::newer_file() +{ struct stat st; time_t file_time; - if(stat(pathname, &st) != 0) + if (stat(pathname, &st) != 0) RETURN_ERRNO(mFALSE, ME_NOFILE); file_time=st.st_ctime > st.st_mtime ? st.st_ctime : st.st_mtime; META_DEBUG(5, ("newer_file? file=%s; load=%d, file=%d; ctime=%d, mtime=%d", file, time_loaded, file_time, st.st_ctime, st.st_mtime)); - if(file_time > time_loaded) - return(mTRUE); + if (file_time > time_loaded) + return mTRUE; else RETURN_ERRNO(mFALSE, ME_NOERROR); } @@ -1360,32 +1392,34 @@ mBOOL DLLINTERNAL MPlugin::newer_file(void) { // SHOW is max 4 chars, for "show" output. // meta_errno values: // - none -const char * DLLINTERNAL MPlugin::str_status(STR_STATUS fmt) { - switch(status) { - case PL_EMPTY: - if(fmt==ST_SHOW) return("empt"); - else return("empty"); - case PL_VALID: - if(fmt==ST_SHOW) return("info"); - else return("valid"); - case PL_BADFILE: - if(fmt==ST_SHOW) return("badf"); - else return("badfile"); - case PL_OPENED: - if(fmt==ST_SHOW) return("open"); - else return("opened"); - case PL_FAILED: - if(fmt==ST_SHOW) return("fail"); - else return("failed"); - case PL_RUNNING: - if(fmt==ST_SHOW) return("RUN"); - else return("running"); - case PL_PAUSED: - if(fmt==ST_SHOW) return("PAUS"); - else return("paused"); - default: - if(fmt==ST_SHOW) return(META_UTIL_VarArgs("UNK%d", status)); - return(META_UTIL_VarArgs("unknown (%d)", status)); +const char *MPlugin::str_status(STR_STATUS fmt) +{ + switch (status) + { + case PL_EMPTY: + if (fmt == ST_SHOW) return "empt"; + else return "empty"; + case PL_VALID: + if (fmt == ST_SHOW) return"info"; + else return "valid"; + case PL_BADFILE: + if (fmt == ST_SHOW) return "badf"; + else return "badfile"; + case PL_OPENED: + if (fmt == ST_SHOW) return "open"; + else return "opened"; + case PL_FAILED: + if (fmt == ST_SHOW) return "fail"; + else return "failed"; + case PL_RUNNING: + if (fmt == ST_SHOW) return "RUN"; + else return "running"; + case PL_PAUSED: + if (fmt == ST_SHOW) return "PAUS"; + else return "paused"; + default: + if (fmt == ST_SHOW) return META_UTIL_VarArgs("UNK%d", status); + return META_UTIL_VarArgs("unknown (%d)", status); } } @@ -1394,32 +1428,34 @@ const char * DLLINTERNAL MPlugin::str_status(STR_STATUS fmt) { // SHOW is max 4 chars, for "show" output. // meta_errno values: // - none -const char * DLLINTERNAL MPlugin::str_action(STR_ACTION fmt) { - switch(action) { - case PA_NULL: - if(fmt==SA_SHOW) return("NULL"); - else return("null"); - case PA_NONE: - if(fmt==SA_SHOW) return(" - "); - else return("none"); - case PA_KEEP: - if(fmt==SA_SHOW) return("keep"); - else return("keep"); - case PA_LOAD: - if(fmt==SA_SHOW) return("load"); - else return("load"); - case PA_ATTACH: - if(fmt==SA_SHOW) return("atch"); - else return("attach"); - case PA_UNLOAD: - if(fmt==SA_SHOW) return("unld"); - else return("unload"); - case PA_RELOAD: - if(fmt==SA_SHOW) return("relo"); - else return("reload"); - default: - if(fmt==SA_SHOW) return(META_UTIL_VarArgs("UNK%d", action)); - else return(META_UTIL_VarArgs("unknown (%d)", action)); +const char *MPlugin::str_action(STR_ACTION fmt) +{ + switch (action) + { + case PA_NULL: + if (fmt == SA_SHOW) return "NULL"; + else return "null"; + case PA_NONE: + if (fmt == SA_SHOW) return " - "; + else return "none"; + case PA_KEEP: + if (fmt == SA_SHOW) return "keep"; + else return "keep"; + case PA_LOAD: + if (fmt == SA_SHOW) return "load"; + else return "load"; + case PA_ATTACH: + if (fmt == SA_SHOW) return "atch"; + else return "attach"; + case PA_UNLOAD: + if (fmt == SA_SHOW) return "unld"; + else return "unload"; + case PA_RELOAD: + if (fmt == SA_SHOW) return "relo"; + else return "reload"; + default: + if (fmt == SA_SHOW) return META_UTIL_VarArgs("UNK%d", action); + else return META_UTIL_VarArgs("unknown (%d)", action); } } @@ -1430,93 +1466,97 @@ const char * DLLINTERNAL MPlugin::str_action(STR_ACTION fmt) { // NOW is to describe current situation of load/unload attempt. // meta_errno values: // - none -const char * DLLINTERNAL MPlugin::str_loadtime(PLUG_LOADTIME ptime, STR_LOADTIME fmt) { - switch(ptime) { - case PT_NEVER: - if(fmt==SL_SHOW) return("Never"); - else return("never"); - case PT_STARTUP: - if(fmt==SL_SHOW) return("Start"); - else if(fmt==SL_ALLOWED) return("at server startup"); - else if(fmt==SL_NOW) return("during server startup"); - else return("startup"); - case PT_CHANGELEVEL: - if(fmt==SL_SHOW) return("Chlvl"); - else if(fmt==SL_ALLOWED) return("at changelevel"); - else if(fmt==SL_NOW) return("during changelevel"); - else return("changelevel"); - case PT_ANYTIME: - if(fmt==SL_SHOW) return("ANY"); - else if(fmt==SL_ALLOWED) return("at any time"); - else if(fmt==SL_NOW) return("during map"); - else return("anytime"); - case PT_ANYPAUSE: - if(fmt==SL_SHOW) return("Pause"); - else if(fmt==SL_ALLOWED) return("at any time, and pausable"); - else if(fmt==SL_NOW) return("for requested pause"); - else return("pausable"); - default: - if(fmt==SL_SHOW) return(META_UTIL_VarArgs("UNK-%d", ptime)); - else return(META_UTIL_VarArgs("unknown (%d)", ptime)); - } +const char *MPlugin::str_loadtime(PLUG_LOADTIME ptime, STR_LOADTIME fmt) +{ + static const char *rPrintLoadTime[][5] = { + // SL_SIMPLE // SL_SHOW // SL_ALLOWED // SL_NOW + { "never", "Never", "never", "never" }, // PT_NEVER + { "startup", "Start", "at server startup", "during server startup" }, // PT_STARTUP + { "changelevel","Chlvl", "at changelevel", "during changelevel" }, // PT_CHANGELEVEL + { "anytime", "ANY", "at any time", "during map" }, // PT_ANYTIME + { "pausable", "Pause", "at any time, and pausable", "for requested pause" }, // PT_ANYPAUSE + }; + + if (ptime >= PT_NEVER || ptime <= PT_ANYPAUSE) + return rPrintLoadTime[ptime][fmt]; + + if (fmt == SL_SHOW) + return META_UTIL_VarArgs("UNK-%d", ptime); + + return META_UTIL_VarArgs("unknown (%d)", ptime); } // Return a string describing why a plugin is to be unloaded. // meta_errno values: // - none -const char * DLLINTERNAL MPlugin::str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason) { +const char *MPlugin::str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason) +{ char buf[128]; - - if(preason == PNL_PLUGIN) + + if (preason == PNL_PLUGIN) preason = PNL_NULL; - if(preason == PNL_PLG_FORCED) + else if (preason == PNL_PLG_FORCED) preason = PNL_NULL; - - switch(preal_reason) { - case PNL_NULL: - return("null"); - case PNL_INI_DELETED: - return("deleted from ini file"); - case PNL_FILE_NEWER: - return("file on disk is newer"); - case PNL_COMMAND: - return("server command"); - case PNL_CMD_FORCED: - return("forced by server command"); - case PNL_PLUGIN: - STRNCPY(buf, str_reason(PNL_NULL, preason), sizeof(buf)); - return(META_UTIL_VarArgs("%s (request from plugin[%d])", buf, unloader_index)); - case PNL_PLG_FORCED: - STRNCPY(buf, str_reason(PNL_NULL, preason), sizeof(buf)); - return(META_UTIL_VarArgs("%s (forced request from plugin[%d])", buf, unloader_index)); - case PNL_RELOAD: - return("reloading"); - default: - return(META_UTIL_VarArgs("unknown (%d)", preal_reason)); + + switch (preal_reason) + { + case PNL_NULL: + return "null"; + case PNL_INI_DELETED: + return "deleted from ini file"; + case PNL_FILE_NEWER: + return "file on disk is newer"; + case PNL_COMMAND: + return "server command"; + case PNL_CMD_FORCED: + return "forced by server command"; + case PNL_PLUGIN: + { + Q_strncpy(buf, str_reason(PNL_NULL, preason), sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + return META_UTIL_VarArgs("%s (request from plugin[%d])", buf, unloader_index); + } + case PNL_PLG_FORCED: + { + Q_strncpy(buf, str_reason(PNL_NULL, preason), sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + return META_UTIL_VarArgs("%s (forced request from plugin[%d])", buf, unloader_index); + } + case PNL_RELOAD: + return "reloading"; + default: + return META_UTIL_VarArgs("unknown (%d)", preal_reason); } } // Return a string describing how the plugin was loaded. // meta_errno values: // - none -const char * DLLINTERNAL MPlugin::str_source(STR_SOURCE fmt) { - switch(source) { - case PS_INI: - if(fmt==SO_SHOW) return("ini"); - else return("ini file"); - case PS_CMD: - if(fmt==SO_SHOW) return("cmd"); - else return("console command"); - case PS_PLUGIN: - if(source_plugin_index <= 0) { - if(fmt==SO_SHOW) return("plUN"); - else return("unloaded plugin"); - } else { - if(fmt==SO_SHOW) return(META_UTIL_VarArgs("pl%d", source_plugin_index)); - else return(META_UTIL_VarArgs("plugin [%d]", source_plugin_index)); - } - default: - if(fmt==SO_SHOW) return(META_UTIL_VarArgs("UNK%d", source)); - else return(META_UTIL_VarArgs("unknown (%d)", source)); +const char *MPlugin::str_source(STR_SOURCE fmt) +{ + switch (source) + { + case PS_INI: + if (fmt == SO_SHOW) return "ini"; + else return "ini file"; + case PS_CMD: + if (fmt == SO_SHOW) return "cmd"; + else return "console command"; + case PS_PLUGIN: + if (source_plugin_index <= 0) + { + if (fmt == SO_SHOW) return "plUN"; + else return "unloaded plugin"; + } + else + { + if (fmt == SO_SHOW) return META_UTIL_VarArgs("pl%d", source_plugin_index); + else return META_UTIL_VarArgs("plugin [%d]", source_plugin_index); + } + default: + if (fmt == SO_SHOW) return META_UTIL_VarArgs("UNK%d", source); + else return META_UTIL_VarArgs("unknown (%d)", source); } } diff --git a/metamod/src/mplugin.h b/metamod/src/mplugin.h new file mode 100644 index 0000000..60dea97 --- /dev/null +++ b/metamod/src/mplugin.h @@ -0,0 +1,184 @@ +#pragma once + +#include "api_info.h" +#include "support_meta.h" + +// Flags to indicate current "load" state of plugin. +// NOTE: order is important, as greater/less comparisons are made. +enum PLUG_STATUS { + PL_EMPTY = 0, // empty slot + PL_VALID, // has valid info in it + PL_BADFILE, // nonexistent file (open failed), + // or not a valid plugin file (query failed) + PL_OPENED, // dlopened and queried + PL_FAILED, // opened, but failed to attach or unattach + PL_RUNNING, // attached and running + PL_PAUSED, // attached but paused +}; + +// Action to take for plugin at next opportunity. +enum PLUG_ACTION { + PA_NULL = 0, + PA_NONE, // no action needed right now + PA_KEEP, // keep, after ini refresh + PA_LOAD, // load (dlopen, query) and try to attach + PA_ATTACH, // attach + PA_UNLOAD, // unload (detach, dlclose) + PA_RELOAD, // unload and load again +}; + +// Flags to indicate from where the plugin was loaded. +enum PLOAD_SOURCE { + PS_INI = 0, // was loaded from the plugins.ini + PS_CMD, // was loaded via a server command + PS_PLUGIN, // was loaded by other plugin +}; + +// Flags for how to word description of plugin loadtime. +enum STR_LOADTIME { + SL_SIMPLE = 0, // single word + SL_SHOW, // for "show" output, 5 chars + SL_ALLOWED, // when plugin is allowed to load/unload + SL_NOW, // current situation +}; + +// Flags for how to format description of status. +enum STR_STATUS { + ST_SIMPLE = 0, // single word + ST_SHOW, // for "show" output, 4 chars +}; + +// Flags for how to format description of action. +enum STR_ACTION { + SA_SIMPLE = 0, // single word + SA_SHOW, // for "show" output, 4 chars +}; + +// Flags for how to format description of source. +enum STR_SOURCE { + SO_SIMPLE = 0, // two words + SO_SHOW, // for "list" output, 3 chars +}; + +// api table list +struct api_tables_t { + enginefuncs_t *engine; + DLL_FUNCTIONS *dllapi; + NEW_DLL_FUNCTIONS *newapi; +}; + +// An individual plugin. +class MPlugin: public class_metamod_new { +public: + mBOOL ini_parseline(const char *line); // parse line from inifile + mBOOL cmd_parseline(const char *line); // parse from console command + mBOOL plugin_parseline(const char *fname, int loader_index); // parse from plugin + mBOOL check_input(); + + mBOOL resolve(); // find a matching file on disk + char *resolve_dirs(const char *path); + char *resolve_prefix(const char *path); + char *resolve_suffix(const char *path); + static mBOOL is_platform_postfix(const char *pf); + + mBOOL platform_match(MPlugin* plugin); + + mBOOL load(PLUG_LOADTIME now); + mBOOL unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason); + mBOOL reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); + mBOOL pause(); + mBOOL unpause(); + mBOOL retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // if previously failed + void free_api_pointers(); + mBOOL clear(); + mBOOL plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // other plugin unloading + void show(); // print info about plugin to console + + mBOOL newer_file(); // check for newer file on disk + + const char *str_status(STR_STATUS fmt); + const char *str_action(STR_ACTION fmt); + const char *str_source(STR_SOURCE fmt); + + const char *str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason); + const char *str_loadtime(PLUG_LOADTIME pallow, STR_LOADTIME fmt); + + inline const char *str_status() { return str_status(ST_SIMPLE); }; + inline const char *str_action() { return str_action(SA_SIMPLE); }; + inline const char *str_source() { return str_source(SO_SIMPLE); }; + + inline const char *str_loadable() { + return info ? str_loadtime(info->loadable, SL_SIMPLE) : " -"; + }; + inline const char *str_unloadable() { + return info ? str_loadtime(info->unloadable, SL_SIMPLE) : " -"; + }; + inline const char *str_loadable(STR_LOADTIME fmt) { + return info ? str_loadtime(info->loadable, fmt) : " -"; + }; + inline const char *str_unloadable(STR_LOADTIME fmt) { + return info ? str_loadtime(info->unloadable, fmt) : " -"; + }; + +public: + // reordered for faster api_hook.cpp functions + PLUG_STATUS status; // current status of plugin (loaded, etc) + api_tables_t tables; + api_tables_t post_tables; + + inline void *get_api_table(enum_api_t api) { + return ((void **)&tables)[api]; + } + inline void *get_api_post_table(enum_api_t api) { + return ((void **)&post_tables)[api]; + } + + int index; // 1-based + int pfspecific; // level of specific platform affinity, used during load time + PLUG_ACTION action; // what to do with plugin (load, unload, etc) + PLOAD_SOURCE source; // source of the request to load the plugin + int source_plugin_index; // index of plugin that loaded this plugin. -1 means source plugin has been unloaded. + int unloader_index; + mBOOL is_unloader; // fix to prevent other plugins unload active unloader. + + DLHANDLE handle; // handle for dlopen, dlsym, etc + plugin_info_t *info; // information plugin provides about itself + time_t time_loaded; // when plugin was loaded + + char filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile + char *file; // ie "mm_test_i386.so", ptr from filename + char desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile + char pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir + +private: + mBOOL query(); + mBOOL attach(PLUG_LOADTIME now); + mBOOL detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); + + gamedll_funcs_t gamedll_funcs; + mutil_funcs_t mutil_funcs; +}; + +// Macros used by MPlugin::show(), to list the functions that the plugin +// catches. +#define SHOW_DEF_API(api_info, api_table, pre_str, post_str) \ + n=0; \ + { \ + const api_info_t * ainfo = (const api_info_t *)&api_info; \ + const void ** table = (const void **)api_table; \ + for (int i = 0; &ainfo[i] < &api_info.END; i++) { \ + if (table[i]) { \ + META_CONS("%s%s%s", pre_str, ainfo[i].name, post_str); \ + n++; \ + } \ + } \ + } + +#define SHOW_DEF_DLLAPI(api_table, pre_str, post_str) \ + SHOW_DEF_API(dllapi_info, api_table, pre_str, post_str) + +#define SHOW_DEF_NEWAPI(api_table, pre_str, post_str) \ + SHOW_DEF_API(newapi_info, api_table, pre_str, post_str) + +#define SHOW_DEF_ENGINE(api_table, pre_str, post_str) \ + SHOW_DEF_API(engine_info, api_table, pre_str, post_str) diff --git a/src/mreg.cpp b/metamod/src/mreg.cpp similarity index 62% rename from src/mreg.cpp rename to metamod/src/mreg.cpp index a900fe0..d42ebdf 100644 --- a/src/mreg.cpp +++ b/metamod/src/mreg.cpp @@ -1,27 +1,8 @@ -#ifdef linux -// enable extra routines in system header files, like strsignal -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#endif /* linux */ - -#include // strsignal, strdup, etc -#include // strerror, etc -#include // always -#include "mreg.h" // me -#include "metamod.h" // Plugins, etc -#include "mlist.h" // class MPluginList -#include "mplugin.h" // class MPlugin -#include "types_meta.h" // mBOOL -#include "log_meta.h" // META_LOG, etc -#include "osdep.h" // os_safe_call, etc - - -///// class MRegCmd: +#include "precompiled.h" // Init values. It would probably be more "proper" to use containers and // constructors, rather than arrays and init-functions. -void DLLINTERNAL MRegCmd::init(int idx) +void MRegCmd::init(int idx) { index = idx; name = NULL; @@ -36,18 +17,19 @@ void DLLINTERNAL MRegCmd::init(int idx) // meta_errno values: // - ME_BADREQ function disabled/invalid // - ME_ARGUMENT function pointer is null -mBOOL DLLINTERNAL MRegCmd::call(void) { +mBOOL MRegCmd::call() +{ mBOOL ret; // can we expect to call this function? - if(status != RG_VALID) + if (status != RG_VALID) RETURN_ERRNO(mFALSE, ME_BADREQ); - if(!pfnCmd) + if (!pfnCmd) RETURN_ERRNO(mFALSE, ME_ARGUMENT); // try to call this function ret=os_safe_call(pfnCmd); - if(!ret) { + if (!ret) { META_DEBUG(4, ("Plugin reg_cmd '%s' called after unloaded; removed from list", name)); status=RG_INVALID; pfnCmd=NULL; @@ -55,32 +37,29 @@ mBOOL DLLINTERNAL MRegCmd::call(void) { // would just re-introduce the segfault problem.. } // meta_errno (if failed) is set already in os_safe_call() - return(ret); + return ret; } - -///// class MRegCmdList: - -// Constructor -MRegCmdList::MRegCmdList(void) +MRegCmdList::MRegCmdList() : mlist(0), size(REG_CMD_GROWSIZE), endlist(0) { - int i; - mlist = (MRegCmd *) calloc(1, size * sizeof(MRegCmd)); + mlist = (MRegCmd *)calloc(1, size * sizeof(MRegCmd)); + // initialize array - for(i=0; i < size; i++) - mlist[i].init(i+1); // 1-based index - endlist=0; + for (int i = 0; i < size; i++) + mlist[i].init(i + 1); // 1-based index + + endlist = 0; } // Try to find a registered function with the given name. // meta_errno values: // - ME_NOTFOUND couldn't find a matching function -MRegCmd * DLLINTERNAL MRegCmdList::find(const char *findname) { +MRegCmd *MRegCmdList::find(const char *findname) { int i; - for(i=0; i < endlist; i++) { - if(!strcasecmp(mlist[i].name, findname)) - return(&mlist[i]); + for (i=0; i < endlist; i++) { + if (!strcasecmp(mlist[i].name, findname)) + return &mlist[i]; } RETURN_ERRNO(NULL, ME_NOTFOUND); } @@ -90,24 +69,24 @@ MRegCmd * DLLINTERNAL MRegCmdList::find(const char *findname) { // (meta_AddServerCommand). // meta_errno values: // - ME_NOMEM couldn't realloc or malloc for various parts -MRegCmd * DLLINTERNAL MRegCmdList::add(const char *addname) { +MRegCmd *MRegCmdList::add(const char *addname) { MRegCmd *icmd; - if(endlist==size) { + if (endlist==size) { // grow array MRegCmd *temp; int i, newsize; newsize=size+REG_CMD_GROWSIZE; META_DEBUG(6, ("Growing reg cmd list from %d to %d", size, newsize)); temp = (MRegCmd *) realloc(mlist, newsize*sizeof(MRegCmd)); - if(!temp) { + if (!temp) { META_WARNING("Couldn't grow registered command list to %d for '%s': %s", newsize, addname, strerror(errno)); RETURN_ERRNO(NULL, ME_NOMEM); } mlist=temp; size=newsize; // initialize new (unused) entries - for(i=endlist; iname=strdup(addname); - if(!icmd->name) { - META_WARNING("Couldn't strdup for adding reg cmd name '%s': %s", + if (!icmd->name) { + META_WARNING("Couldn't strdup for adding reg cmd name '%s': %s", addname, strerror(errno)); RETURN_ERRNO(NULL, ME_NOMEM); } endlist++; - - return(icmd); + + return icmd; } // Disable any functions belonging to the given plugin (by index id). -void DLLINTERNAL MRegCmdList::disable(int plugin_id) { +void MRegCmdList::disable(int plugin_id) { int i; - for(i=0; i < size; i++) { - if(mlist[i].plugid == plugin_id) + for (i=0; i < size; i++) { + if (mlist[i].plugid == plugin_id) mlist[i].status = RG_INVALID; } } // List all the registered commands. -void DLLINTERNAL MRegCmdList::show(void) { +void MRegCmdList::show() +{ int i, n=0, a=0; MRegCmd *icmd; MPlugin *iplug; char bplug[18+1]; // +1 for term null META_CONS("Registered plugin commands:"); - META_CONS(" %*s %-*s %-s", - WIDTH_MAX_REG, "", - sizeof(bplug)-1, "plugin", "command"); - - for(i=0; i < endlist; i++) { + META_CONS(" %*s %-*s %-s", WIDTH_MAX_REG, "", sizeof(bplug)-1, "plugin", "command"); + + for (i = 0; i < endlist; i++) + { icmd = &mlist[i]; - - if(icmd->status==RG_VALID) { + + if (icmd->status == RG_VALID) + { iplug=Plugins->find(icmd->plugid); - - if(iplug) - STRNCPY(bplug, iplug->desc, sizeof(bplug)); + + if (iplug) + { + Q_strncpy(bplug, iplug->desc, sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } else - STRNCPY(bplug, "(unknown)", sizeof(bplug)); + { + Q_strncpy(bplug, "(unknown)", sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } } else - STRNCPY(bplug, "(unloaded)", sizeof(bplug)); - - META_CONS(" [%*d] %-*s %-s", - WIDTH_MAX_REG, icmd->index, - sizeof(bplug)-1, bplug, - icmd->name); - - if(icmd->status==RG_VALID) + { + Q_strncpy(bplug, "(unloaded)", sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } + + META_CONS(" [%*d] %-*s %-s", WIDTH_MAX_REG, icmd->index, sizeof(bplug)-1, bplug, icmd->name); + + if (icmd->status == RG_VALID) a++; - + n++; } - + META_CONS("%d commands, %d available (%d allocated)", n, a, size); } // List all the registered commands for the given plugin id. -void DLLINTERNAL MRegCmdList::show(int plugin_id) { +void MRegCmdList::show(int plugin_id) { int i, n=0; MRegCmd *icmd; - + /* // If OS doesn't support DLFNAME, then we can't know what the plugin's // registered cvars are. DLFNAME(NULL); - if(meta_errno==ME_OSNOTSUP) { + if (meta_errno==ME_OSNOTSUP) { META_CONS("Registered commands: unknown (can't get info under this OS)"); return; } */ - + META_CONS("Registered commands:"); - for(i=0; i < endlist; i++) { + for (i=0; i < endlist; i++) { icmd = &mlist[i]; - if(icmd->plugid != plugin_id) + if (icmd->plugid != plugin_id) continue; META_CONS(" %s", icmd->name); n++; @@ -210,7 +196,7 @@ void DLLINTERNAL MRegCmdList::show(int plugin_id) { // Init values. It would probably be more "proper" to use containers and // constructors, rather than arrays and init-functions. -void DLLINTERNAL MRegCvar::init(int idx) +void MRegCvar::init(int idx) { index = idx; data = NULL; @@ -221,8 +207,8 @@ void DLLINTERNAL MRegCvar::init(int idx) // Set the cvar, copying values from given cvar. // meta_errno values: // - ME_ARGUMENT given cvar doesn't match this cvar -mBOOL DLLINTERNAL MRegCvar::set(cvar_t *src) { - if(strcasecmp(src->name, data->name)) { +mBOOL MRegCvar::set(cvar_t *src) { + if (strcasecmp(src->name, data->name)) { META_WARNING("Tried to set cvar with mismatched name; src=%s dst=%s", src->name, data->name); RETURN_ERRNO(mFALSE, ME_ARGUMENT); @@ -233,20 +219,17 @@ mBOOL DLLINTERNAL MRegCvar::set(cvar_t *src) { data->flags = src->flags; data->value = src->value; data->next = src->next; - return(mTRUE); + return mTRUE; } - -///// class MRegCvarList: - // Constructor -MRegCvarList::MRegCvarList(void) +MRegCvarList::MRegCvarList() : vlist(0), size(REG_CVAR_GROWSIZE), endlist(0) { int i; vlist = (MRegCvar *) calloc(1, size * sizeof(MRegCvar)); // initialize array - for(i=0; i < size; i++) + for (i=0; i < size; i++) vlist[i].init(i+1); // 1-based endlist=0; } @@ -256,24 +239,24 @@ MRegCvarList::MRegCvarList(void) // cvar::set(). // meta_errno values: // - ME_NOMEM couldn't alloc or realloc for various parts -MRegCvar * DLLINTERNAL MRegCvarList::add(const char *addname) { +MRegCvar *MRegCvarList::add(const char *addname) { MRegCvar *icvar; - if(endlist==size) { + if (endlist==size) { // grow array MRegCvar *temp; int i, newsize; newsize=size+REG_CVAR_GROWSIZE; META_DEBUG(6, ("Growing reg cvar list from %d to %d", size, newsize)); temp = (MRegCvar *) realloc(vlist, newsize*sizeof(MRegCvar)); - if(!temp) { + if (!temp) { META_WARNING("Couldn't grow registered cvar list to %d for '%s'; %s", newsize, addname, strerror(errno)); RETURN_ERRNO(NULL, ME_NOMEM); } vlist=temp; size=newsize; // initialize new (unused) entries - for(i=endlist; idata = (cvar_t *) calloc(1, sizeof(cvar_t)); - if(!icvar->data) { - META_WARNING("Couldn't malloc cvar for adding reg cvar name '%s': %s", + if (!icvar->data) { + META_WARNING("Couldn't malloc cvar for adding reg cvar name '%s': %s", addname, strerror(errno)); RETURN_ERRNO(NULL, ME_NOMEM); } icvar->data->name=strdup(addname); - if(!icvar->data->name) { - META_WARNING("Couldn't strdup for adding reg cvar name '%s': %s", + if (!icvar->data->name) { + META_WARNING("Couldn't strdup for adding reg cvar name '%s': %s", addname, strerror(errno)); RETURN_ERRNO(NULL, ME_NOMEM); } endlist++; - - return(icvar); + + return icvar; } // Try to find a registered cvar with the given name. // meta_errno values: // - ME_NOTFOUND couldn't find a matching cvar -MRegCvar * DLLINTERNAL MRegCvarList::find(const char *findname) { +MRegCvar *MRegCvarList::find(const char *findname) { int i; - for(i=0; i < endlist; i++) { - if(!strcasecmp(vlist[i].data->name, findname)) - return(&vlist[i]); + for (i=0; i < endlist; i++) { + if (!strcasecmp(vlist[i].data->name, findname)) + return &vlist[i]; } RETURN_ERRNO(NULL, ME_NOTFOUND); } // Disable any cvars belonging to the given plugin (by index id). -void DLLINTERNAL MRegCvarList::disable(int plugin_id) { +void MRegCvarList::disable(int plugin_id) { int i; MRegCvar *icvar; - for(i=0; i < size; i++) { + for (i=0; i < size; i++) { icvar=&vlist[i]; - if(icvar->plugid == plugin_id) { + if (icvar->plugid == plugin_id) { icvar->status = RG_INVALID; icvar->plugid = 0; // Decided not to do this, in order to keep pre-existing values @@ -332,40 +315,51 @@ void DLLINTERNAL MRegCvarList::disable(int plugin_id) { } // List all the registered cvars. -void DLLINTERNAL MRegCvarList::show(void) { +void MRegCvarList::show() { int i, n=0, a=0; MRegCvar *icvar; MPlugin *iplug; char bplug[13+1], bname[20+1], bval[15+1]; // +1 for term null META_CONS("Registered plugin cvars:"); - META_CONS(" %*s %-*s %-*s %*s %s", - WIDTH_MAX_REG, "", - sizeof(bplug)-1, "plugin", - sizeof(bname)-1, "cvar", - sizeof(bval)-1, "float value", - "string value"); - - for(i=0; i < endlist; i++) { + META_CONS(" %*s %-*s %-*s %*s %s", WIDTH_MAX_REG, "", sizeof(bplug)-1, "plugin", sizeof(bname)-1, "cvar", sizeof(bval)-1, "float value", "string value"); + + for (i=0; i < endlist; i++) + { icvar = &vlist[i]; - if(icvar->status==RG_VALID) { + if (icvar->status==RG_VALID) + { iplug=Plugins->find(icvar->plugid); - if(iplug) - STRNCPY(bplug, iplug->desc, sizeof(bplug)); + if (iplug) + { + Q_strncpy(bplug, iplug->desc, sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } else - STRNCPY(bplug, "(unknown)", sizeof(bplug)); + { + Q_strncpy(bplug, "(unknown)", sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } } else - STRNCPY(bplug, "(unloaded)", sizeof(bplug)); - STRNCPY(bname, icvar->data->name, sizeof(bname)); + { + Q_strncpy(bplug, "(unloaded)", sizeof(bplug) - 1); + bplug[sizeof(bplug) - 1] = '\0'; + } + + Q_strncpy(bname, icvar->data->name, sizeof(bname) - 1); + bname[sizeof(bname) - 1] = '\0'; + safevoid_snprintf(bval, sizeof(bval), "%f", icvar->data->value); - META_CONS(" [%*d] %-*s %-*s %*s %s", - WIDTH_MAX_REG, icvar->index, + + META_CONS(" [%*d] %-*s %-*s %*s %s", + WIDTH_MAX_REG, icvar->index, sizeof(bplug)-1, bplug, sizeof(bname)-1, bname, sizeof(bval)-1, bval, icvar->data->string); - if(icvar->status==RG_VALID) + + if (icvar->status==RG_VALID) a++; n++; } @@ -373,51 +367,37 @@ void DLLINTERNAL MRegCvarList::show(void) { } // List the registered cvars for the given plugin id. -void DLLINTERNAL MRegCvarList::show(int plugin_id) { +void MRegCvarList::show(int plugin_id) { int i, n=0; MRegCvar *icvar; char bname[30+1], bval[15+1]; // +1 for term null - - /* - // If OS doesn't support DLFNAME, then we can't know what the plugin's - // registered cvars are. - DLFNAME(NULL); - if(meta_errno==ME_OSNOTSUP) { - META_CONS("Registered cvars: unknown (can't get info under this OS)"); - return; - } - */ - - META_CONS("%-*s %*s %s", - sizeof(bname)-1, "Registered cvars:", - sizeof(bval)-1, "float value", - "string value"); - for(i=0; i < endlist; i++) { + + META_CONS("%-*s %*s %s", sizeof(bname)-1, "Registered cvars:", sizeof(bval) - 1, "float value", "string value"); + for (i = 0; i < endlist; i++) + { icvar = &vlist[i]; - if(icvar->plugid != plugin_id) + if (icvar->plugid != plugin_id) continue; - STRNCPY(bname, icvar->data->name, sizeof(bname)); + + Q_strncpy(bname, icvar->data->name, sizeof(bname) - 1); + bname[sizeof(bname) - 1] = '\0'; + safevoid_snprintf(bval, sizeof(bval), "%f", icvar->data->value); - META_CONS(" %-*s %*s %s", - sizeof(bname)-1, bname, - sizeof(bval)-1, bval, - icvar->data->string); + META_CONS(" %-*s %*s %s", sizeof(bname)-1, bname, sizeof(bval)-1, bval, icvar->data->string); n++; } - META_CONS("%d cvars", n); + + META_CONS("%d cvars", n); } - -///// class MRegMsgList: - // Constructor -MRegMsgList::MRegMsgList(void) +MRegMsgList::MRegMsgList() : size(MAX_REG_MSGS), endlist(0) { int i; // initialize array Q_memset(mlist, 0, sizeof(mlist)); - for(i=0; i < size; i++) { + for (i=0; i < size; i++) { mlist[i].index=i+1; // 1-based } endlist=0; @@ -426,10 +406,10 @@ MRegMsgList::MRegMsgList(void) // Add the given user msg the list and return the instance. // meta_errno values: // - ME_MAXREACHED reached max number of msgs allowed -MRegMsg * DLLINTERNAL MRegMsgList::add(const char *addname, int addmsgid, int addsize) { +MRegMsg *MRegMsgList::add(const char *addname, int addmsgid, int addsize) { MRegMsg *imsg; - if(endlist==size) { + if (endlist==size) { // all slots used META_ERROR("Couldn't add registered msg '%s' to list; reached max msgs (%d)", addname, size); @@ -446,49 +426,55 @@ MRegMsg * DLLINTERNAL MRegMsgList::add(const char *addname, int addmsgid, int ad imsg->msgid=addmsgid; imsg->size=addsize; - return(imsg); + return imsg; } // Try to find a registered msg with the given name. // meta_errno values: // - ME_NOTFOUND couldn't find a matching cvar -MRegMsg * DLLINTERNAL MRegMsgList::find(const char *findname) { - int i; - for(i=0; i < endlist; i++) { - if(!mm_strcmp(mlist[i].name, findname)) - return(&mlist[i]); +MRegMsg *MRegMsgList::find(const char *findname) +{ + for (int i = 0; i < endlist; i++) + { + if (!Q_strcmp(mlist[i].name, findname)) + return &mlist[i]; } + RETURN_ERRNO(NULL, ME_NOTFOUND); } // Try to find a registered msg with the given msgid. // meta_errno values: // - ME_NOTFOUND couldn't find a matching cvar -MRegMsg * DLLINTERNAL MRegMsgList::find(int findmsgid) { - int i; - for(i=0; i < endlist; i++) { - if(mlist[i].msgid == findmsgid) - return(&mlist[i]); +MRegMsg *MRegMsgList::find(int findmsgid) +{ + for (int i = 0; i < endlist; i++) + { + if (mlist[i].msgid == findmsgid) + return &mlist[i]; } + RETURN_ERRNO(NULL, ME_NOTFOUND); } // List the registered usermsgs for the gamedll. -void DLLINTERNAL MRegMsgList::show(void) { - int i, n=0; +void MRegMsgList::show() +{ + int i, n = 0; MRegMsg *imsg; char bname[25+1]; // +1 for term null - META_CONS("%-*s %5s %5s", - sizeof(bname)-1, "Game registered user msgs:", "msgid", "size"); - for(i=0; i < endlist; i++) { + META_CONS("%-*s %5s %5s", sizeof(bname)-1, "Game registered user msgs:", "msgid", "size"); + for (i = 0; i < endlist; i++) + { imsg = &mlist[i]; - STRNCPY(bname, imsg->name, sizeof(bname)); - META_CONS(" %-*s %3d %3d", - sizeof(bname)-1, bname, - imsg->msgid, - imsg->size); + + Q_strncpy(bname, imsg->name, sizeof(bname) - 1); + bname[sizeof(bname) - 1] = '\0'; + + META_CONS(" %-*s %3d %3d", sizeof(bname)-1, bname, imsg->msgid, imsg->size); n++; } - META_CONS("%d game user msgs", n); + + META_CONS("%d game user msgs", n); } diff --git a/metamod/src/mreg.h b/metamod/src/mreg.h new file mode 100644 index 0000000..969d68c --- /dev/null +++ b/metamod/src/mreg.h @@ -0,0 +1,137 @@ +#pragma once + +#include "types_meta.h" // mBOOL +#include "comp_dep.h" // +#include "new_baseclass.h" + +// Number of entries to add to reglists when they need to grow. Typically +// more cvars than commands, so we grow them at different increments. +#define REG_CMD_GROWSIZE 32 +#define REG_CVAR_GROWSIZE 64 + +// Width required to printf a Reg*List index number, for show() functions. +// This used to correspond to the number of digits in MAX_REG, which was a +// fixed, compile-time limit. However, now that the reg lists are grown +// dynamically, this has less strong correspondance to list sizes. So for +// the moment, it reflects what one might normally expect to be the max +// width needed to print an index number; 4 allows 9999 (which is a damn +// lot, if you ask me). +#define WIDTH_MAX_REG 4 + +// Max number of registered user msgs we can manage. +#define MAX_REG_MSGS 256 + +// Max number of clients on server +#define MAX_CLIENTS_CONNECTED 32 + +// Flags to indicate if given cvar or func is part of a loaded plugin. +enum REG_STATUS { RG_INVALID, RG_VALID }; + +// Pointer to function registered by AddServerCommand. +typedef void (*REG_CMD_FN)(); + +// An individual registered function/command. +class MRegCmd: public class_metamod_new +{ +public: + friend class MRegCmdList; + + char *name; // space is malloc'd + REG_CMD_FN pfnCmd; // pointer to the function + int plugid; // index id of corresponding plugin + REG_STATUS status; // whether corresponding plugin is loaded + + void init(int idx); // init values, as not using constructors + mBOOL call(); // try to call the function + +private: + int index; // 1-based +}; + +// A list of registered commands. +class MRegCmdList : public class_metamod_new { +public: + MRegCmdList(); + + MRegCmd *find(const char *findname); // find by MRegCmd->name + MRegCmd *add(const char *addname); + void disable(int plugin_id); // change status to Invalid + void show(); // list all funcs to console + void show(int plugin_id); // list given plugin's funcs to console + +private: + MRegCmd *mlist; // malloc'd array of registered commands + int size; // current size of list + int endlist; // index of last used entry + + // Private; to satisfy -Weffc++ "has pointer data members but does + // not override" copy/assignment constructor. + void operator=(const MRegCmdList &src); + MRegCmdList(const MRegCmdList &src); +}; + +// An individual registered cvar. +class MRegCvar : public class_metamod_new { +public: + friend class MRegCvarList; + + cvar_t *data; // actual cvar structure, malloc'd + int plugid; // index id of corresponding plugin + REG_STATUS status; // whether corresponding plugin is loaded + + void init(int idx); // init values, as not using constructors + mBOOL set(cvar_t *src); +private: + int index; // 1-based +}; + +// A list of registered cvars. +class MRegCvarList: public class_metamod_new { +public: + MRegCvarList(); + + MRegCvar *add(const char *addname); + MRegCvar *find(const char *findname); // find by MRegCvar->data.name + void disable(int plugin_id); // change status to Invalid + void show(); // list all cvars to console + void show(int plugin_id); // list given plugin's cvars to console + +private: + MRegCvar *vlist; // malloc'd array of registered cvars + int size; // size of list, ie MAX_REG_CVARS + int endlist; // index of last used entry + + // Private; to satisfy -Weffc++ "has pointer data members but does + // not override" copy/assignment constructor. + void operator=(const MRegCvarList &src); + MRegCvarList(const MRegCvarList &src); +}; + +// An individual registered user msg, from gamedll. +class MRegMsg: public class_metamod_new { +public: + friend class MRegMsgList; + + const char *name; // name, assumed constant string in gamedll + int msgid; // msgid, assigned by engine + int size; // size, if given by gamedll + +private: + int index; // 1-based +}; + +// A list of registered user msgs. +class MRegMsgList: public class_metamod_new { +public: + MRegMsgList(); + + MRegMsg *add(const char *addname, int addmsgid, int addsize); + MRegMsg *find(const char *findname); + MRegMsg *find(int findmsgid); + void show(); // list all msgs to console + +private: + MRegMsg mlist[MAX_REG_MSGS]; // array of registered msgs + int size; // size of list, ie MAX_REG_MSGS + int endlist; // index of last used entry +}; diff --git a/src/mutil.cpp b/metamod/src/mutil.cpp similarity index 64% rename from src/mutil.cpp rename to metamod/src/mutil.cpp index c48d68e..e852ac5 100644 --- a/src/mutil.cpp +++ b/metamod/src/mutil.cpp @@ -1,14 +1,4 @@ -#include // vsnprintf(), etc -#include // vs_start(), etc -#include // strtol() -#include // always -#include "meta_api.h" // -#include "mutil.h" // me -#include "linkent.h" // ENTITY_FN, etc -#include "metamod.h" // Hooks, etc -#include "types_meta.h" // mBOOL -#include "osdep.h" // win32 vsnprintf, etc -#include "sdk_util.h" // ALERT, etc +#include "precompiled.h" static hudtextparms_t default_csay_tparms = { -1, 0.25, // x, y @@ -29,7 +19,7 @@ static void mutil_LogConsole(plid_t /* plid */, const char *fmt, ...) { va_end(ap); // end msg with newline len=Q_strlen(buf); - if(len < sizeof(buf)-2) // -1 null, -1 for newline + if (len < sizeof(buf)-2) // -1 null, -1 for newline Q_strcat(buf, "\n"); else buf[len-1] = '\n'; @@ -65,7 +55,7 @@ static void mutil_LogDeveloper(plid_t plid, const char *fmt, ...) { va_list ap; char buf[MAX_LOGMSG_LEN]; plugin_info_t *plinfo; - if((int)CVAR_GET_FLOAT("developer") == 0) + if ((int)CVAR_GET_FLOAT("developer") == 0) return; plinfo=(plugin_info_t *)plid; va_start(ap, fmt); @@ -76,15 +66,15 @@ static void mutil_LogDeveloper(plid_t plid, const char *fmt, ...) { // Print a center-message, with text parameters and varargs. Provides // functionality to the above center_say interfaces. -static void mutil_CenterSayVarargs(plid_t plid, hudtextparms_t tparms, - const char *fmt, va_list ap) +static void mutil_CenterSayVarargs(plid_t plid, hudtextparms_t tparms, + const char *fmt, va_list ap) { char buf[MAX_LOGMSG_LEN]; int n; edict_t *pEntity; safevoid_vsnprintf(buf, sizeof(buf), fmt, ap); mutil_LogMessage(plid, "(centersay) %s", buf); - for(n=1; n <= gpGlobals->maxClients; n++) { + for (n=1; n <= gpGlobals->maxClients; n++) { pEntity=INDEXENT(n); META_UTIL_HudMessage(pEntity, tparms, buf); } @@ -117,14 +107,14 @@ static qboolean mutil_CallGameEntity(plid_t plid, const char *entStr, entvars_t META_DEBUG(8, ("Looking up game entity '%s' for plugin '%s'", entStr, plinfo->name)); pfnEntity = (ENTITY_FN) DLSYM(GameDLL.handle, entStr); - if(!pfnEntity) { + if (!pfnEntity) { META_WARNING("Couldn't find game entity '%s' in game DLL '%s' for plugin '%s'", entStr, GameDLL.name, plinfo->name); - return(false); + return false; } META_DEBUG(7, ("Calling game entity '%s' for plugin '%s'", entStr, plinfo->name)); (*pfnEntity)(pev); - return(true); + return true; } // Find a usermsg, registered by the gamedll, with the corresponding @@ -137,13 +127,13 @@ static int mutil_GetUserMsgID(plid_t plid, const char *msgname, int *size) { META_DEBUG(8, ("Looking up usermsg name '%s' for plugin '%s'", msgname, plinfo->name)); umsg=RegMsgs->find(msgname); - if(umsg) { - if(size) + if (umsg) { + if (size) *size=umsg->size; - return(umsg->msgid); + return umsg->msgid; } else - return(0); + return 0; } // Find a usermsg, registered by the gamedll, with the corresponding @@ -157,38 +147,40 @@ static const char *mutil_GetUserMsgName(plid_t plid, int msgid, int *size) { plinfo->name)); // Guess names for any built-in Engine messages mentioned in the SDK; // from dlls/util.h. - if(msgid < 64) { - switch(msgid) { - case SVC_TEMPENTITY: - if(size) *size=-1; - return("tempentity?"); - case SVC_INTERMISSION: - if(size) *size=-1; - return("intermission?"); - case SVC_CDTRACK: - if(size) *size=-1; - return("cdtrack?"); - case SVC_WEAPONANIM: - if(size) *size=-1; - return("weaponanim?"); - case SVC_ROOMTYPE: - if(size) *size=-1; - return("roomtype?"); - case SVC_DIRECTOR: - if(size) *size=-1; - return("director?"); + if (msgid < 64) { + switch (msgid) + { + case SVC_TEMPENTITY: + if (size) *size = -1; + return "tempentity?"; + case SVC_INTERMISSION: + if (size) *size = -1; + return "intermission?"; + case SVC_CDTRACK: + if (size) *size = -1; + return "cdtrack?"; + case SVC_WEAPONANIM: + if (size) *size = -1; + return "weaponanim?"; + case SVC_ROOMTYPE: + if (size) *size = -1; + return "roomtype?"; + case SVC_DIRECTOR: + if (size) *size = -1; + return "director?"; } } - umsg=RegMsgs->find(msgid); - if(umsg) { - if(size) - *size=umsg->size; + umsg = RegMsgs->find(msgid); + if (umsg) + { + if (size) + *size = umsg->size; // 'name' is assumed to be a constant string, allocated in the // gamedll. - return(umsg->name); + return umsg->name; } - else - return(NULL); + + return nullptr; } // Return the full path of the plugin's loaded dll/so file. @@ -196,65 +188,72 @@ static const char *mutil_GetPluginPath(plid_t plid) { static char buf[PATH_MAX]; MPlugin *plug; - plug=Plugins->find(plid); - if(!plug) { - META_WARNING("GetPluginPath: couldn't find plugin '%s'", - plid->name); - return(NULL); + plug = Plugins->find(plid); + if (!plug) + { + META_WARNING("GetPluginPath: couldn't find plugin '%s'", plid->name); + return nullptr; } - STRNCPY(buf, plug->pathname, sizeof(buf)); - return(buf); + + Q_strncpy(buf, plug->pathname, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + return buf; } // Return various string-based info about the game/MOD/gamedll. -static const char *mutil_GetGameInfo(plid_t plid, ginfo_t type) { +const char *mutil_GetGameInfo(plid_t plid, ginfo_t type) +{ static char buf[MAX_STRBUF_LEN]; const char *cp; - switch(type) { - case GINFO_NAME: - cp=GameDLL.name; - break; - case GINFO_DESC: - cp=GameDLL.desc; - break; - case GINFO_GAMEDIR: - cp=GameDLL.gamedir; - break; - case GINFO_DLL_FULLPATH: - cp=GameDLL.pathname; - break; - case GINFO_DLL_FILENAME: - cp=GameDLL.file; - break; - case GINFO_REALDLL_FULLPATH: - cp=GameDLL.real_pathname; - break; - default: - META_WARNING("GetGameInfo: invalid request '%d' from plugin '%s'", - type, plid->name); - return(NULL); + switch (type) + { + case GINFO_NAME: + cp = GameDLL.name; + break; + case GINFO_DESC: + cp = GameDLL.desc; + break; + case GINFO_GAMEDIR: + cp = GameDLL.gamedir; + break; + case GINFO_DLL_FULLPATH: + cp = GameDLL.pathname; + break; + case GINFO_DLL_FILENAME: + cp = GameDLL.file; + break; + case GINFO_REALDLL_FULLPATH: + cp = GameDLL.real_pathname; + break; + default: + META_WARNING("GetGameInfo: invalid request '%d' from plugin '%s'", type, plid->name); + return nullptr; } - STRNCPY(buf, cp, sizeof(buf)); - return(buf); + + Q_strncpy(buf, cp, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + + return buf; } -static int mutil_LoadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, void **plugin_handle) +int mutil_LoadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME now, void **plugin_handle) { MPlugin *pl_loaded; - - if(NULL == fname) { - return(ME_ARGUMENT); + + if (NULL == fname) { + return ME_ARGUMENT; } meta_errno = ME_NOERROR; - if(!(pl_loaded=Plugins->plugin_addload(plid, fname, now))) { - if(plugin_handle) + if (!(pl_loaded=Plugins->plugin_addload(plid, fname, now))) { + if (plugin_handle) *plugin_handle = NULL; - return(meta_errno); + return meta_errno; } else { - if(plugin_handle) + if (plugin_handle) *plugin_handle = (void*)pl_loaded->handle; - return(0); + return 0; } } @@ -264,54 +263,54 @@ static int mutil_UnloadMetaPlugin(plid_t plid, const char *fname, PLUG_LOADTIME int pindex; char* endptr; - if(NULL == fname) { - return(ME_ARGUMENT); + if (NULL == fname) { + return ME_ARGUMENT; } pindex = strtol(fname, &endptr, 10); - if(*fname != '\0' && *endptr == '\0') + if (*fname != '\0' && *endptr == '\0') findp = Plugins->find(pindex); else findp = Plugins->find_match(fname); - if(!findp) - return(meta_errno); + if (!findp) + return meta_errno; meta_errno = ME_NOERROR; - if(findp->plugin_unload(plid, now, reason)) - return(0); - - return(meta_errno); + if (findp->plugin_unload(plid, now, reason)) + return 0; + + return meta_errno; } static int mutil_UnloadMetaPluginByHandle(plid_t plid, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason) { MPlugin *findp; - if(NULL == plugin_handle) { - return(ME_ARGUMENT); + if (NULL == plugin_handle) { + return ME_ARGUMENT; } - if(!(findp=Plugins->find((DLHANDLE)plugin_handle))) - return(ME_NOTFOUND); - + if (!(findp=Plugins->find((DLHANDLE)plugin_handle))) + return ME_NOTFOUND; + meta_errno = ME_NOERROR; - if(findp->plugin_unload(plid, now, reason)) - return(0); + if (findp->plugin_unload(plid, now, reason)) + return 0; - return(meta_errno); + return meta_errno; } // Check if player is being queried for cvar static const char * mutil_IsQueryingClientCvar(plid_t /*plid*/, const edict_t *player) { - return(g_Players.is_querying_cvar(player)); + return g_Players.is_querying_cvar(player); } // static int mutil_MakeRequestID(plid_t /*plid*/) { - return(abs(0xbeef<<16) + (++requestid_counter)); + return abs(0xbeef<<16) + (++requestid_counter); } // @@ -331,17 +330,17 @@ mutil_funcs_t MetaUtilFunctions = { mutil_LogError, // pfnLogError mutil_LogDeveloper, // pfnLogDeveloper mutil_CenterSay, // pfnCenterSay - mutil_CenterSayParms, // pfnCenterSayParms - mutil_CenterSayVarargs, // pfnCenterSayVarargs - mutil_CallGameEntity, // pfnCallGameEntity + mutil_CenterSayParms, // pfnCenterSayParms + mutil_CenterSayVarargs, // pfnCenterSayVarargs + mutil_CallGameEntity, // pfnCallGameEntity mutil_GetUserMsgID, // pfnGetUserMsgID - mutil_GetUserMsgName, // pfnGetUserMsgName - mutil_GetPluginPath, // pfnGetPluginPath + mutil_GetUserMsgName, // pfnGetUserMsgName + mutil_GetPluginPath, // pfnGetPluginPath mutil_GetGameInfo, // pfnGetGameInfo - mutil_LoadMetaPlugin, // pfnLoadPlugin - mutil_UnloadMetaPlugin, // pfnUnloadPlugin - mutil_UnloadMetaPluginByHandle, // pfnUnloadPluginByHandle - mutil_IsQueryingClientCvar, // pfnIsQueryingClientCvar - mutil_MakeRequestID, // pfnMakeRequestID - mutil_GetHookTables, // pfnGetHookTables + mutil_LoadMetaPlugin, // pfnLoadPlugin + mutil_UnloadMetaPlugin, // pfnUnloadPlugin + mutil_UnloadMetaPluginByHandle, // pfnUnloadPluginByHandle + mutil_IsQueryingClientCvar, // pfnIsQueryingClientCvar + mutil_MakeRequestID, // pfnMakeRequestID + mutil_GetHookTables, // pfnGetHookTables }; diff --git a/src/mutil.h b/metamod/src/mutil.h similarity index 98% rename from src/mutil.h rename to metamod/src/mutil.h index f7e3ada..7936cd1 100644 --- a/src/mutil.h +++ b/metamod/src/mutil.h @@ -40,7 +40,7 @@ typedef struct meta_util_funcs_s { void (*pfnGetHookTables) (plid_t plid, enginefuncs_t **peng, DLL_FUNCTIONS **pdll, NEW_DLL_FUNCTIONS **pnewdll); } mutil_funcs_t; -extern mutil_funcs_t MetaUtilFunctions DLLHIDDEN; +extern mutil_funcs_t MetaUtilFunctions; // Convenience macros for MetaUtil functions #define LOG_CONSOLE (*gpMetaUtilFuncs->pfnLogConsole) diff --git a/metamod/src/new_baseclass.h b/metamod/src/new_baseclass.h new file mode 100644 index 0000000..b5854af --- /dev/null +++ b/metamod/src/new_baseclass.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include "comp_dep.h" + +// new/delete operators with malloc/free to remove need for libstdc++ + +class class_metamod_new { +public: + // Construction + class_metamod_new() { }; + // Operators + inline void * operator new(size_t size) + { + if (size==0) + return calloc(1, 1); + return calloc(1, size); + } + + inline void * operator new[](size_t size) + { + if (size==0) + return calloc(1, 1); + return calloc(1, size); + } + + inline void operator delete(void *ptr) + { + if (ptr) + free(ptr); + } + + inline void operator delete[](void *ptr) + { + if (ptr) + free(ptr); + } +}; diff --git a/src/osdep.cpp b/metamod/src/osdep.cpp similarity index 72% rename from src/osdep.cpp rename to metamod/src/osdep.cpp index 1c5aad3..d0cce7d 100644 --- a/src/osdep.cpp +++ b/metamod/src/osdep.cpp @@ -1,57 +1,47 @@ -#ifdef linux -// enable extra routines in system header files, like dladdr -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#include // dlopen, dladdr, etc -#endif /* linux */ - -#include // strpbrk, etc -#include // always -#include "osdep.h" // me -#include "mreg.h" // RG_VALID, etc -#include "log_meta.h" // META_ERROR, etc -#include "types_meta.h" // mBOOL -#include "support_meta.h" // MAX_STRBUF_LEN -#include "limits.h" // INT_MAX +#include "precompiled.h" mBOOL dlclose_handle_invalid; #ifdef _WIN32 + +#ifdef _MSC_VER +#pragma comment(lib, "psapi.lib") // Process Status API +#endif // _MSC_VER + // Since windows doesn't provide a verison of strtok_r(), we include one // here. This may or may not operate exactly like strtok_r(), but does // what we need it it do. -char * DLLINTERNAL my_strtok_r(char *s, const char *delim, char **ptrptr) { +char *my_strtok_r(char *s, const char *delim, char **ptrptr) { char *begin=NULL; char *end=NULL; char *rest=NULL; - if(s) + if (s) begin=s; else begin=*ptrptr; - if(!begin) - return(NULL); + if (!begin) + return NULL; end=strpbrk(begin, delim); - if(end) { + if (end) { *end='\0'; rest=end+1; *ptrptr=rest+strspn(rest, delim); } else *ptrptr=NULL; - return(begin); + return begin; } #endif /* _WIN32 */ #ifdef linux -char * DLLINTERNAL my_strlwr(char *s) { +char *my_strlwr(char *s) { char *c; - if(!s) - return(0); - for(c=s;*c;c++) + if (!s) + return 0; + for (c=s;*c;c++) *c = tolower(*c); - return(s); + return s; } #endif @@ -60,118 +50,119 @@ char * DLLINTERNAL my_strlwr(char *s) { // Microsoft's msvcrt.dll:vsnprintf is buggy and so is vsnprintf on some glibc versions. // We use wrapper function to fix bugs. // from: http://sourceforge.net/tracker/index.php?func=detail&aid=1083721&group_id=2435&atid=102435 -int DLLINTERNAL safe_vsnprintf(char* s, size_t n, const char *format, va_list src_ap) { +int safe_vsnprintf(char* s, size_t n, const char *format, va_list src_ap) { va_list ap; int res; char *tmpbuf; size_t bufsize = n; - - if(s && n>0) + + if (s && n>0) s[0]=0; - + // If the format string is empty, nothing to do. - if(!format || !*format) - return(0); - + if (!format || !*format) + return 0; + // The supplied count may be big enough. Try to use the library // vsnprintf, fixing up the case where the library function // neglects to terminate with '/0'. - if(n > 0) + if (n > 0) { // A NULL destination will cause a segfault with vsnprintf. // if n > 0. Nor do we want to copy our tmpbuf to NULL later. - if(!s) - return(-1); - + if (!s) + return -1; + va_copy(ap, src_ap); res = Q_vsnprintf(s, n, format, ap); va_end(ap); - - if(res > 0) { - if((unsigned)res == n) + + if (res > 0) { + if ((unsigned)res == n) s[res - 1] = 0; - return(res); + return res; } - + // If n is already larger than INT_MAX, increasing it won't // help. - if(n > INT_MAX) - return(-1); - + if (n > INT_MAX) + return -1; + // Try a larger buffer. bufsize *= 2; } - - if(bufsize < 1024) + + if (bufsize < 1024) bufsize = 1024; - + tmpbuf = (char *)malloc(bufsize * sizeof(char)); - if(!tmpbuf) - return(-1); - + if (!tmpbuf) + return -1; + va_copy(ap, src_ap); res = Q_vsnprintf(tmpbuf, bufsize, format, ap); va_end(ap); - + // The test for bufsize limit is probably not necesary // with 2GB address space limit, since, in practice, malloc will // fail well before INT_MAX. - while(res < 0 && bufsize <= INT_MAX) { + while (res < 0 && bufsize <= INT_MAX) + { char * newbuf; - + bufsize *= 2; newbuf = (char*)realloc(tmpbuf, bufsize * sizeof(char)); - - if(!newbuf) + + if (!newbuf) break; - + tmpbuf = newbuf; - + va_copy(ap, src_ap); res = Q_vsnprintf(tmpbuf, bufsize, format, ap); va_end(ap); } - - if(res > 0 && n > 0) { - if(n > (unsigned)res) + + if (res > 0 && n > 0) { + if (n > (unsigned)res) Q_memcpy(s, tmpbuf, (res + 1) * sizeof (char)); else { Q_memcpy(s, tmpbuf, (n - 1) * sizeof (char)); s[n - 1] = 0; } } - + free(tmpbuf); - return(res); + return res; } -int DLLINTERNAL safe_snprintf(char* s, size_t n, const char* format, ...) { +int safe_snprintf(char* s, size_t n, const char* format, ...) { int res; va_list ap; va_start(ap, format); res = safe_vsnprintf(s, n, format, ap); va_end(ap); - return(res); + return res; } #endif -void DLLINTERNAL safevoid_vsnprintf(char* s, size_t n, const char *format, va_list ap) { +void safevoid_vsnprintf(char* s, size_t n, const char *format, va_list ap) { int res; - if(!s || n <= 0) + if (!s || n <= 0) return; // If the format string is empty, nothing to do. - if(!format || !*format) { + if (!format || !*format) { s[0]=0; return; } res = Q_vsnprintf(s, n, format, ap); // w32api returns -1 on too long write, glibc returns number of bytes it could have written if there were enough space // w32api doesn't write null at all, some buggy glibc don't either - if(res < 0 || (size_t)res >= n) + if (res < 0 || (size_t)res >= n) s[n-1]=0; } -void DLLINTERNAL safevoid_snprintf(char* s, size_t n, const char* format, ...) { +void safevoid_snprintf(char* s, size_t n, const char* format, ...) { va_list ap; va_start(ap, format); safevoid_vsnprintf(s, n, format, ap); @@ -185,13 +176,13 @@ void DLLINTERNAL safevoid_snprintf(char* s, size_t n, const char* format, ...) { // http://msdn.microsoft.com/library/en-us/debug/errors_0sdh.asp // except without FORMAT_MESSAGE_ALLOCATE_BUFFER, since we use a local // static buffer. -char * DLLINTERNAL str_GetLastError(void) { +char *str_GetLastError() { static char buf[MAX_STRBUF_LEN]; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //! Default language + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //! Default language (LPTSTR) &buf, MAX_STRBUF_LEN-1, NULL); - return(buf); + return buf; } #endif /* _WIN32 */ @@ -201,11 +192,11 @@ char * DLLINTERNAL str_GetLastError(void) { #ifdef linux // Errno values: // - ME_NOTFOUND couldn't find a sharedlib that contains memory location -const char * DLLINTERNAL DLFNAME(void *memptr) { +const char *DLFNAME(void *memptr) { Dl_info dli; Q_memset(&dli, 0, sizeof(dli)); - if(dladdr(memptr, &dli)) - return(dli.dli_fname); + if (dladdr(memptr, &dli)) + return dli.dli_fname; else RETURN_ERRNO(NULL, ME_NOTFOUND); } @@ -231,28 +222,28 @@ const char * DLLINTERNAL DLFNAME(void *memptr) { // // Errno values: // - ME_NOTFOUND couldn't find a DLL that contains memory location -const char * DLLINTERNAL DLFNAME(void *memptr) { +const char *DLFNAME(void *memptr) { MEMORY_BASIC_INFORMATION MBI; static char fname[PATH_MAX]; Q_memset(fname, 0, sizeof(fname)); - if(!VirtualQuery(memptr, &MBI, sizeof(MBI))) + if (!VirtualQuery(memptr, &MBI, sizeof(MBI))) RETURN_ERRNO(NULL, ME_NOTFOUND); - if(MBI.State != MEM_COMMIT) + if (MBI.State != MEM_COMMIT) RETURN_ERRNO(NULL, ME_NOTFOUND); - if(!MBI.AllocationBase) + if (!MBI.AllocationBase) RETURN_ERRNO(NULL, ME_NOTFOUND); - + // MSDN indicates that GetModuleFileName will leave string // null-terminated, even if it's truncated because buffer is too small. - if(!GetModuleFileNameA((HMODULE)MBI.AllocationBase, fname, sizeof(fname)-1)) + if (!GetModuleFileNameA((HMODULE)MBI.AllocationBase, fname, sizeof(fname)-1)) RETURN_ERRNO(NULL, ME_NOTFOUND); - if(!fname[0]) + if (!fname[0]) RETURN_ERRNO(NULL, ME_NOTFOUND); - + normalize_pathname(fname); - return(fname); + return fname; } #endif /* _WIN32 */ @@ -266,15 +257,15 @@ const char * DLLINTERNAL DLFNAME(void *memptr) { // non-case-sensitive. // - For linux, this requires no work, as paths uses slashes (/) natively, // and pathnames are case-sensitive. -void DLLINTERNAL normalize_pathname(char *path) { +void normalize_pathname(char *path) { char *cp; META_DEBUG(8, ("normalize: %s", path)); - for(cp=path; *cp; cp++) { - /*if(isupper(*cp))*/ + for (cp=path; *cp; cp++) { + /*if (isupper(*cp))*/ *cp=tolower(*cp); - - if(*cp=='\\') + + if (*cp=='\\') *cp='/'; } META_DEBUG(8, ("normalized: %s", path)); @@ -282,27 +273,27 @@ void DLLINTERNAL normalize_pathname(char *path) { // Buffer pointed to by resolved_name is assumed to be able to store a // string of PATH_MAX length. -char * DLLINTERNAL realpath(const char *file_name, char *resolved_name) { +char *realpath(const char *file_name, char *resolved_name) { int ret; ret=GetFullPathNameA(file_name, PATH_MAX, resolved_name, NULL); - if(ret > PATH_MAX) { + if (ret > PATH_MAX) { errno=ENAMETOOLONG; - return(NULL); + return nullptr; } - else if(ret > 0) { + else if (ret > 0) { HANDLE handle; WIN32_FIND_DATAA find_data; handle=FindFirstFileA(resolved_name, &find_data); - if(INVALID_HANDLE_VALUE == handle) { + if (INVALID_HANDLE_VALUE == handle) { errno=ENOENT; - return(NULL); + return nullptr; } FindClose(handle); normalize_pathname(resolved_name); - return(resolved_name); + return resolved_name; } - else - return(NULL); + else + return nullptr; } #endif /*_WIN32*/ @@ -316,11 +307,11 @@ char * DLLINTERNAL realpath(const char *file_name, char *resolved_name) { // we need it for in this particular situation. // meta_errno values: // - ME_NOTFOUND couldn't find a matching sharedlib for this ptr -mBOOL DLLINTERNAL IS_VALID_PTR(void *memptr) { +mBOOL IS_VALID_PTR(void *memptr) { Dl_info dli; Q_memset(&dli, 0, sizeof(dli)); - if(dladdr(memptr, &dli)) - return(mTRUE); + if (dladdr(memptr, &dli)) + return mTRUE; else RETURN_ERRNO(mFALSE, ME_NOTFOUND); } @@ -328,11 +319,11 @@ mBOOL DLLINTERNAL IS_VALID_PTR(void *memptr) { // Use the native windows routine IsBadCodePtr. // meta_errno values: // - ME_BADMEMPTR not a valid memory pointer -mBOOL DLLINTERNAL IS_VALID_PTR(void *memptr) { - if(IsBadCodePtr((FARPROC) memptr)) +mBOOL IS_VALID_PTR(void *memptr) { + if (IsBadCodePtr((FARPROC) memptr)) RETURN_ERRNO(mFALSE, ME_BADMEMPTR); else - return(mTRUE); + return mTRUE; } #endif /* _WIN32 */ @@ -341,12 +332,12 @@ mBOOL DLLINTERNAL IS_VALID_PTR(void *memptr) { // in plugin commands and produced confusing output ("plugin has been // unloaded", when really it segfaultd), and (b) wasn't necessary since // IS_VALID_PTR() should cover the situation. -mBOOL DLLINTERNAL os_safe_call(REG_CMD_FN pfn) { +mBOOL os_safe_call(REG_CMD_FN pfn) { // try and see if this is a valid memory location - if(!IS_VALID_PTR((void *) pfn)) + if (!IS_VALID_PTR((void *) pfn)) // meta_errno should be already set in is_valid_ptr() - return(mFALSE); + return mFALSE; pfn(); - return(mTRUE); + return mTRUE; } diff --git a/src/osdep.h b/metamod/src/osdep.h similarity index 57% rename from src/osdep.h rename to metamod/src/osdep.h index abf3744..8f17cae 100644 --- a/src/osdep.h +++ b/metamod/src/osdep.h @@ -1,5 +1,4 @@ -#ifndef OSDEP_H -#define OSDEP_H +#pragma once #include // strerror() #include // isupper, tolower @@ -13,21 +12,15 @@ #include "log_meta.h" // LOG_ERROR, etc // String describing platform/DLL-type, for matching lines in plugins.ini. -#ifdef linux - #define PLATFORM "linux" -# if defined(__x86_64__) || defined(__amd64__) - #define PLATFORM_SPC "lin64" -# else - #define PLATFORM_SPC "lin32" -# endif - #define PLATFORM_DLEXT ".so" -#elif defined(_WIN32) +#ifdef _WIN32 #define PLATFORM "mswin" #define PLATFORM_SPC "win32" #define PLATFORM_DLEXT ".dll" -#else /* unknown */ - #error "OS unrecognized" -#endif /* unknown */ +#else + #define PLATFORM "linux" + #define PLATFORM_SPC "lin32" + #define PLATFORM_DLEXT ".so" +#endif // Macro for function-exporting from DLL.. // from SDK dlls/cbase.h: @@ -74,92 +67,96 @@ // Special version that fixes vsnprintf bugs. #ifndef DO_NOT_FIX_VARARG_ENGINE_API_WARPERS -int DLLINTERNAL safe_vsnprintf(char* s, size_t n, const char *format, va_list ap); -int DLLINTERNAL safe_snprintf(char* s, size_t n, const char* format, ...); +int safe_vsnprintf(char* s, size_t n, const char *format, va_list ap); +int safe_snprintf(char* s, size_t n, const char* format, ...); #endif -void DLLINTERNAL safevoid_vsnprintf(char* s, size_t n, const char *format, va_list ap); -void DLLINTERNAL safevoid_snprintf(char* s, size_t n, const char* format, ...); +void safevoid_vsnprintf(char* s, size_t n, const char *format, va_list ap); +void safevoid_snprintf(char* s, size_t n, const char* format, ...); // Functions & types for DLL open/close/etc operations. -extern mBOOL dlclose_handle_invalid DLLHIDDEN; -#ifdef linux - #include - typedef void* DLHANDLE; - typedef void* DLFUNC; - inline DLHANDLE DLLINTERNAL DLOPEN(const char *filename) - { - return(dlopen(filename, RTLD_NOW)); - } - inline DLFUNC DLLINTERNAL DLSYM(DLHANDLE handle, const char *string) - { - return(dlsym(handle, string)); - } - //dlclose crashes if handle is null. - inline int DLLINTERNAL DLCLOSE(DLHANDLE handle) - { - if(!handle) - { - dlclose_handle_invalid = mTRUE; - return(1); - } - dlclose_handle_invalid = mFALSE; - return(dlclose(handle)); - } - inline const char * DLLINTERNAL DLERROR(void) - { - if(dlclose_handle_invalid) - return("Invalid handle."); - return(dlerror()); - } -#elif defined(_WIN32) +extern mBOOL dlclose_handle_invalid; +#ifdef _WIN32 typedef HINSTANCE DLHANDLE; typedef FARPROC DLFUNC; - inline DLHANDLE DLLINTERNAL DLOPEN(const char *filename) + inline DLHANDLE DLOPEN(const char *filename) { - return(LoadLibraryA(filename)); + return LoadLibraryA(filename); } - inline DLFUNC DLLINTERNAL DLSYM(DLHANDLE handle, const char *string) + inline DLFUNC DLSYM(DLHANDLE handle, const char *string) { - return(GetProcAddress(handle, string)); + return GetProcAddress(handle, string); } - inline int DLLINTERNAL DLCLOSE(DLHANDLE handle) + inline int DLCLOSE(DLHANDLE handle) { - if(!handle) + if (!handle) { dlclose_handle_invalid = mTRUE; - return(1); + return 1; } + dlclose_handle_invalid = mFALSE; // NOTE: Windows FreeLibrary returns success=nonzero, fail=zero, // which is the opposite of the unix convention, thus the '!'. - return(!FreeLibrary(handle)); + return !FreeLibrary(handle); } // Windows doesn't provide a function corresponding to dlerror(), so // we make our own. - char * DLLINTERNAL str_GetLastError(void); - inline const char * DLLINTERNAL DLERROR(void) { - if(dlclose_handle_invalid) - return("Invalid handle."); - return(str_GetLastError()); + char *str_GetLastError(); + inline const char *DLERROR() + { + if (dlclose_handle_invalid) + return "Invalid handle."; + + return str_GetLastError(); } -#endif /* _WIN32 */ -const char * DLLINTERNAL DLFNAME(void *memptr); -mBOOL DLLINTERNAL IS_VALID_PTR(void *memptr); +#else + typedef void *DLHANDLE; + typedef void *DLFUNC; + inline DLHANDLE DLOPEN(const char *filename) + { + return dlopen(filename, RTLD_NOW); + } + inline DLFUNC DLSYM(DLHANDLE handle, const char *string) + { + return dlsym(handle, string); + } + // dlclose crashes if handle is null. + inline int DLCLOSE(DLHANDLE handle) + { + if (!handle) + { + dlclose_handle_invalid = mTRUE; + return 1; + } + dlclose_handle_invalid = mFALSE; + return dlclose(handle); + } + inline const char *DLERROR() + { + if (dlclose_handle_invalid) + return "Invalid handle."; + + return dlerror(); + } +#endif + +const char *DLFNAME(void *memptr); +mBOOL IS_VALID_PTR(void *memptr); // Attempt to call the given function pointer, without segfaulting. -mBOOL DLLINTERNAL os_safe_call(REG_CMD_FN pfn); +mBOOL os_safe_call(REG_CMD_FN pfn); // Windows doesn't have an strtok_r() routine, so we write our own. #ifdef _WIN32 #define strtok_r(s, delim, ptrptr) my_strtok_r(s, delim, ptrptr) - char * DLLINTERNAL my_strtok_r(char *s, const char *delim, char **ptrptr); + char *my_strtok_r(char *s, const char *delim, char **ptrptr); #endif /* _WIN32 */ // Linux doesn't have an strlwr() routine, so we write our own. #ifdef linux #define strlwr(s) my_strlwr(s) - char * DLLINTERNAL my_strlwr(char *s); + char *my_strlwr(char *s); #endif /* _WIN32 */ @@ -185,11 +182,11 @@ mBOOL DLLINTERNAL os_safe_call(REG_CMD_FN pfn); #include // sleep #ifndef O_BINARY #define O_BINARY 0 - #endif + #endif #elif defined(_WIN32) #include #include - + #define sleep(x) Sleep(x*1000) // Fixed MSVC compiling, by Nikolay "The Storm" Baklicharov. @@ -227,7 +224,7 @@ mBOOL DLLINTERNAL os_safe_call(REG_CMD_FN pfn); #ifndef S_IWUSR #define S_IWUSR _S_IWRITE #endif - + // The following two are defined neither in mingw nor in MSVC #ifndef S_IRGRP #define S_IRGRP S_IRUSR @@ -248,7 +245,7 @@ mBOOL DLLINTERNAL os_safe_call(REG_CMD_FN pfn); #ifdef linux #define normalize_pathname(a) #elif defined(_WIN32) -void DLLINTERNAL normalize_pathname(char *path); +void normalize_pathname(char *path); #endif /* _WIN32 */ // Indicate if pathname appears to be an absolute-path. Under linux this @@ -257,94 +254,28 @@ void DLLINTERNAL normalize_pathname(char *path); // - a toplevel path (ie "\blah") // - a UNC network address (ie "\\srv1\blah"). // Also, handle both native and normalized pathnames. -inline mBOOL DLLINTERNAL is_absolute_path(const char *path) { - if(path[0]=='/') return(mTRUE); +inline mBOOL is_absolute_path(const char *path) { + if (path[0]=='/') return mTRUE; #ifdef _WIN32 - if(path[1]==':') return(mTRUE); - if(path[0]=='\\') return(mTRUE); + if (path[1]==':') return mTRUE; + if (path[0]=='\\') return mTRUE; #endif /* _WIN32 */ - return(mFALSE); + return mFALSE; } #ifdef _WIN32 // Buffer pointed to by resolved_name is assumed to be able to store a // string of PATH_MAX length. -char * DLLINTERNAL realpath(const char *file_name, char *resolved_name); +char *realpath(const char *file_name, char *resolved_name); #endif /* _WIN32 */ // Generic "error string" from a recent OS call. For linux, this is based // on errno. For win32, it's based on GetLastError. -inline const char * DLLINTERNAL str_os_error(void) +inline const char *str_os_error() { -#ifdef linux - return(strerror(errno)); -#elif defined(_WIN32) - return(str_GetLastError()); -#endif /* _WIN32 */ -} - -//#define Q_functions - -#ifndef Q_functions - -#ifndef _WIN32 -#define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]); +#ifdef _WIN32 + return str_GetLastError(); +#else + return strerror(errno); #endif - -#include -//#include "stddef.h" - -#define Q_memset A_memset -#define Q_memcpy A_memcpy -#define Q_memmove A_memmove -#define Q_strlen A_strlen -#define Q_memcmp A_memcmp -#define Q_strcpy A_strcpy -#define Q_strncpy strncpy -#define Q_strrchr strrchr -#define Q_strcat A_strcat -#define Q_strncat strncat -#define Q_strcmp A_strcmp -#define Q_strncmp strncmp -//#define Q_strcasecmp _stricmp // Use Q_stricmp -//#define Q_strncasecmp _strnicmp // Use Q_strnicmp -#define Q_stricmp A_stricmp -#define Q_strnicmp _strnicmp -#define Q_strstr A_strstr -#define Q_strchr strchr -#define Q_strlwr A_strtolower -#define Q_sprintf sprintf -#define Q_snprintf _snprintf -#define Q_atoi atoi -#define Q_atof atof -//#define Q_strtoull strtoull -//#define Q_FileNameCmp FileNameCmp -#define Q_vsnprintf _vsnprintf - -#else // Q_functions - -#define NOBODY -void Q_strcpy(char *dest, const char *src); -int Q_strlen(const char *str); -NOBODY void Q_memset(void *dest, int fill, int count); -NOBODY void Q_memcpy(void *dest, const void *src, int count); -NOBODY int Q_memcmp(void *m1, void *m2, int count); -NOBODY void Q_strncpy(char *dest, const char *src, int count); -NOBODY char *Q_strrchr(char *s, char c); -NOBODY void Q_strcat(char *dest, char *src); -NOBODY int Q_strcmp(const char *s1, const char *s2); -NOBODY int Q_strncmp(const char *s1, const char *s2, int count); -NOBODY int Q_strncasecmp(const char *s1, const char *s2, int n); -NOBODY int Q_strcasecmp(const char *s1, const char *s2); -NOBODY int Q_stricmp(const char *s1, const char *s2); -NOBODY int Q_strnicmp(const char *s1, const char *s2, int n); -NOBODY int Q_atoi(const char *str); -NOBODY float Q_atof(const char *str); -NOBODY char *Q_strlwr(char *src); -NOBODY int Q_FileNameCmp(char *file1, char *file2); -NOBODY char *Q_strstr(const char *s1, const char *search); -NOBODY uint64 Q_strtoull(char *str); - -#endif // Q_functions - -#endif /* OSDEP_H */ +} diff --git a/src/osdep_detect_gamedll_linux.cpp b/metamod/src/osdep_detect_gamedll_linux.cpp similarity index 63% rename from src/osdep_detect_gamedll_linux.cpp rename to metamod/src/osdep_detect_gamedll_linux.cpp index 077a6ee..ec17f9d 100644 --- a/src/osdep_detect_gamedll_linux.cpp +++ b/metamod/src/osdep_detect_gamedll_linux.cpp @@ -1,18 +1,4 @@ -// enable extra routines in system header files, like dladdr -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#include // dlopen, dladdr, etc -#include // sigaction, etc -#include // sigsetjmp, longjmp, etc -#include // mmap, munmap, mprotect, etc -#include -#include - -#include // always - -#include "osdep_p.h" // me -#include "support_meta.h" // STRNCPY +#include "precompiled.h" /* * GLIBC 2.11+ intercept longjmp with __longjmp_chk. However we want @@ -40,10 +26,10 @@ static void signal_handler_sigsegv(int) { sigaction(SIGSEGV, &oldaction, 0); \ META_DEBUG(3, ("is_gamedll(%s): Invalid ELF.", filename)); \ munmap(ehdr, filesize); \ - return(mFALSE); \ - } while(0) + return mFALSE; \ + } while (0) -mBOOL DLLINTERNAL is_gamedll(const char *filename) { +mBOOL is_gamedll(const char *filename) { // When these are not static there are some mysterious hidden bugs that I can't find/solve. // So this is simple workaround. static struct sigaction action; @@ -62,7 +48,7 @@ mBOOL DLLINTERNAL is_gamedll(const char *filename) { static int has_GiveFnptrsToDll = 0; static int has_GetEntityAPI2 = 0; static int has_GetEntityAPI = 0; - + ehdr = 0; shdr = 0; symtab = 0; @@ -77,49 +63,46 @@ mBOOL DLLINTERNAL is_gamedll(const char *filename) { has_GiveFnptrsToDll = 0; has_GetEntityAPI2 = 0; has_GetEntityAPI = 0; - + // Try open file and get filesize - if((pf = fopen(filename, "rb"))) { + if ((pf = fopen(filename, "rb"))) { fseek(pf, 0, SEEK_END); filesize = ftell(pf); fseek(pf, 0, SEEK_SET); } else { META_DEBUG(3, ("is_gamedll(%s): Failed, cannot fopen() file.", filename)); - - return(mFALSE); + + return mFALSE; } - + // Check that filesize is atleast size of ELF header! - if(filesize < sizeof(ElfW(Ehdr))) { -#ifdef __x86_64__ - META_DEBUG(3, ("is_gamedll(%s): Failed, file is too small to be ELF64. [%i < %i]", filename, filesize, sizeof(ElfW(Ehdr)))); -#else + if (filesize < sizeof(ElfW(Ehdr))) + { META_DEBUG(3, ("is_gamedll(%s): Failed, file is too small to be ELF32. [%i < %i]", filename, filesize, sizeof(ElfW(Ehdr)))); -#endif fclose(pf); - - return(mFALSE); + + return mFALSE; } - + // mmap library for easy reading ehdr = (ElfW(Ehdr) *)mmap(0, filesize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(pf), 0); file_end = (unsigned long)ehdr + filesize; - + // not needed anymore fclose(pf); - + // check if mmap was successful - if(!ehdr || (void*)ehdr==(void*)-1) { + if (!ehdr || (void*)ehdr==(void*)-1) { META_DEBUG(3, ("is_gamedll(%s): Failed, mmap() [0x%x]", filename, ehdr)); - - return(mFALSE); + + return mFALSE; } - + //In case that ELF file is incomplete (because bad upload etc), we protect memory-mapping access with signal-handler - if(!setjmp(signal_jmp_buf)) { + if (!setjmp(signal_jmp_buf)) { Q_memset(&action, 0, sizeof(struct sigaction)); Q_memset(&oldaction, 0, sizeof(struct sigaction)); - + // Not returning from signal, set SIGSEGV handler. action.sa_handler = signal_handler_sigsegv; action.sa_flags = SA_RESETHAND | SA_NODEFER; @@ -128,177 +111,143 @@ mBOOL DLLINTERNAL is_gamedll(const char *filename) { } else { // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - + META_DEBUG(3, ("is_gamedll(%s): Failed, signal SIGSEGV.", filename)); - + munmap(ehdr, filesize); - - return(mFALSE); - } - - if(mm_strncmp((char *)ehdr, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { - // Reset signal handler. - sigaction(SIGSEGV, &oldaction, 0); - - META_DEBUG(3, ("is_gamedll(%s): Failed, file isn't ELF (%02x%02x%02x%02x:%x).", filename, - ((char *)ehdr)[0], ((char *)ehdr)[1], ((char *)ehdr)[2], ((char *)ehdr)[3], ehdr->e_ident[EI_VERSION])); - - munmap(ehdr, filesize); - - return(mFALSE); + + return mFALSE; } -#ifdef __x86_64__ - // check if x86_64-shared-library - if(ehdr->e_ident[EI_CLASS] != ELFCLASS64 || ehdr->e_type != ET_DYN || ehdr->e_machine != EM_X86_64) { + if (Q_strncmp((char *)ehdr, ELFMAG, SELFMAG) != 0 || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - - META_DEBUG(3, ("is_gamedll(%s): Failed, ELF isn't for target:x86_64. [%x:%x:%x]", filename, - ehdr->e_ident[EI_CLASS], ehdr->e_type, ehdr->e_machine)); - + + META_DEBUG(3, ("is_gamedll(%s): Failed, file isn't ELF (%02x%02x%02x%02x:%x).", filename, ((char *)ehdr)[0], ((char *)ehdr)[1], ((char *)ehdr)[2], ((char *)ehdr)[3], ehdr->e_ident[EI_VERSION])); + munmap(ehdr, filesize); - - return(mFALSE); + return mFALSE; } -#else + // check if x86-shared-library - if(ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_type != ET_DYN || ehdr->e_machine != EM_386) { + if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 || ehdr->e_type != ET_DYN || ehdr->e_machine != EM_386) + { // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - - META_DEBUG(3, ("is_gamedll(%s): Failed, ELF isn't for target:i386. [%x:%x:%x]", filename, - ehdr->e_ident[EI_CLASS], ehdr->e_type, ehdr->e_machine)); - + + META_DEBUG(3, ("is_gamedll(%s): Failed, ELF isn't for target:i386. [%x:%x:%x]", filename, ehdr->e_ident[EI_CLASS], ehdr->e_type, ehdr->e_machine)); munmap(ehdr, filesize); - - return(mFALSE); + return mFALSE; } -#endif //Get symtab and strtab info shdr = (ElfW(Shdr) *)((char *)ehdr + ehdr->e_shoff); - if(invalid_elf_ptr(shdr[ehdr->e_shnum])) + if (invalid_elf_ptr(shdr[ehdr->e_shnum])) elf_error_exit(); - - for(i = 0; i < ehdr->e_shnum; i++) { + + for (i = 0; i < ehdr->e_shnum; i++) { // searching for dynamic linker symbol table - if(shdr[i].sh_type == SHT_DYNSYM) { - if(invalid_elf_offset(shdr[i].sh_offset) || + if (shdr[i].sh_type == SHT_DYNSYM) { + if (invalid_elf_offset(shdr[i].sh_offset) || invalid_elf_ptr(shdr[shdr[i].sh_link]) || invalid_elf_offset(shdr[shdr[i].sh_link].sh_offset) || invalid_elf_ptr(strtab[strtab_size]) || invalid_elf_ptr(symtab[nsyms])) elf_error_exit(); - + symtab = (ElfW(Sym) *)((char *)ehdr + shdr[i].sh_offset); strtab = (char *)((char *)ehdr + shdr[shdr[i].sh_link].sh_offset); strtab_size = shdr[shdr[i].sh_link].sh_size; nsyms = shdr[i].sh_size / shdr[i].sh_entsize; - + break; } } - - if(!symtab) { + + if (!symtab) { //Another method for finding symtab - for(i = 0; i < ehdr->e_shnum; i++) { - if(shdr[i].sh_type == SHT_SYMTAB) { - if(invalid_elf_offset(shdr[i].sh_offset) || + for (i = 0; i < ehdr->e_shnum; i++) { + if (shdr[i].sh_type == SHT_SYMTAB) { + if (invalid_elf_offset(shdr[i].sh_offset) || invalid_elf_ptr(shdr[shdr[i].sh_link]) || invalid_elf_offset(shdr[shdr[i].sh_link].sh_offset) || invalid_elf_ptr(strtab[strtab_size]) || invalid_elf_ptr(symtab[nsyms])) elf_error_exit(); - + symtab = (ElfW(Sym) *)((char *)ehdr + shdr[i].sh_offset); strtab = (char *)((char *)ehdr + shdr[shdr[i].sh_link].sh_offset); strtab_size = shdr[shdr[i].sh_link].sh_size; nsyms = shdr[i].sh_size / shdr[i].sh_entsize; - + break; } } } - - if(!symtab) { + + if (!symtab) { // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - META_DEBUG(3, ("is_gamedll(%s): Failed, couldn't locate symtab.", filename)); - munmap(ehdr, filesize); - - return(mFALSE); + return mFALSE; } - + //Search symbols for exports - for(i = 0; i < nsyms; i++) { -#ifdef __x86_64__ + for (i = 0; i < nsyms; i++) + { // Export? - if(ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC || ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) + if (ELF32_ST_TYPE(symtab[i].st_info) != STT_FUNC || ELF32_ST_BIND(symtab[i].st_info) != STB_GLOBAL) continue; -#else - // Export? - if(ELF32_ST_TYPE(symtab[i].st_info) != STT_FUNC || ELF32_ST_BIND(symtab[i].st_info) != STB_GLOBAL) - continue; -#endif - + // string outside strtab? - if(symtab[i].st_name <= 0 || symtab[i].st_name >= strtab_size) + if (symtab[i].st_name <= 0 || symtab[i].st_name >= strtab_size) continue; - + funcname = &strtab[symtab[i].st_name]; - + // Check // Fast check for 'G' first - if(funcname[0] == 'G') { + if (funcname[0] == 'G') { // Collect export information - if(!has_GiveFnptrsToDll) - has_GiveFnptrsToDll = strmatch(funcname, "GiveFnptrsToDll"); - if(!has_GetEntityAPI2) - has_GetEntityAPI2 = strmatch(funcname, "GetEntityAPI2"); - if(!has_GetEntityAPI) - has_GetEntityAPI = strmatch(funcname, "GetEntityAPI"); + if (!has_GiveFnptrsToDll) + has_GiveFnptrsToDll = !Q_strcmp(funcname, "GiveFnptrsToDll"); + if (!has_GetEntityAPI2) + has_GetEntityAPI2 = !Q_strcmp(funcname, "GetEntityAPI2"); + if (!has_GetEntityAPI) + has_GetEntityAPI = !Q_strcmp(funcname, "GetEntityAPI"); } // Check if metamod plugin - else if(funcname[0] == 'M') { - if(strmatch(funcname, "Meta_Init") || - strmatch(funcname, "Meta_Query") || - strmatch(funcname, "Meta_Attach") || - strmatch(funcname, "Meta_Detach")) { + else if (funcname[0] == 'M') + { + if (!Q_strcmp(funcname, "Meta_Init") || !Q_strcmp(funcname, "Meta_Query") || !Q_strcmp(funcname, "Meta_Attach") || !Q_strcmp(funcname, "Meta_Detach")) + { // Metamod plugin.. is not gamedll META_DEBUG(5, ("is_gamedll(%s): Detected Metamod plugin, library exports [%s].", filename, funcname)); - + // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - munmap(ehdr, filesize); - - return(mFALSE); + return mFALSE; } } } - + // Check if gamedll - if(has_GiveFnptrsToDll && (has_GetEntityAPI2 || has_GetEntityAPI)) { + if (has_GiveFnptrsToDll && (has_GetEntityAPI2 || has_GetEntityAPI)) { // This is gamedll! META_DEBUG(5, ("is_gamedll(%s): Detected GameDLL.", filename)); - + // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - munmap(ehdr, filesize); - - return(mTRUE); + return mTRUE; } else { META_DEBUG(5, ("is_gamedll(%s): Library isn't GameDLL.", filename)); } - + // Reset signal handler. sigaction(SIGSEGV, &oldaction, 0); - munmap(ehdr, filesize); - - return(mFALSE); + return mFALSE; } diff --git a/src/osdep_detect_gamedll_win32.cpp b/metamod/src/osdep_detect_gamedll_win32.cpp similarity index 59% rename from src/osdep_detect_gamedll_win32.cpp rename to metamod/src/osdep_detect_gamedll_win32.cpp index 6ea4f3b..854f6d8 100644 --- a/src/osdep_detect_gamedll_win32.cpp +++ b/metamod/src/osdep_detect_gamedll_win32.cpp @@ -1,6 +1,4 @@ -#include // always -#include "osdep_p.h" // me -#include "support_meta.h" // STRNCPY +#include "precompiled.h" //check for invalid handle values #define is_invalid_handle(X) ((X)==0 || (X)==INVALID_HANDLE_VALUE) @@ -10,60 +8,59 @@ //virtual address to relative virtual address #define va_to_rva(base, va) ((unsigned long)va - (unsigned long)base) -// -static unsigned long DLLINTERNAL_NOVIS va_to_mapaddr(void * mapview, IMAGE_SECTION_HEADER * sections, int num_sects, unsigned long vaddr) { - for(int i = 0; i < num_sects; i++) - if(vaddr >= sections[i].VirtualAddress && vaddr < sections[i].VirtualAddress + sections[i].SizeOfRawData) - return(rva_to_va(mapview, (vaddr - sections[i].VirtualAddress + sections[i].PointerToRawData))); - - return(0); +unsigned long va_to_mapaddr(void * mapview, IMAGE_SECTION_HEADER * sections, int num_sects, unsigned long vaddr) { + for (int i = 0; i < num_sects; i++) + if (vaddr >= sections[i].VirtualAddress && vaddr < sections[i].VirtualAddress + sections[i].SizeOfRawData) + return rva_to_va(mapview, (vaddr - sections[i].VirtualAddress + sections[i].PointerToRawData)); + + return 0; } // Checks module signatures and return ntheaders pointer for valid module -static IMAGE_NT_HEADERS * DLLINTERNAL_NOVIS get_ntheaders(void * mapview) { - union { +IMAGE_NT_HEADERS *get_ntheaders(void * mapview) { + union { unsigned long mem; IMAGE_DOS_HEADER * dos; IMAGE_NT_HEADERS * pe; } mem; - + //Check if valid dos header mem.mem = (unsigned long)mapview; - if(IsBadReadPtr(mem.dos, sizeof(*mem.dos)) || mem.dos->e_magic != IMAGE_DOS_SIGNATURE) - return(0); - + if (IsBadReadPtr(mem.dos, sizeof(*mem.dos)) || mem.dos->e_magic != IMAGE_DOS_SIGNATURE) + return 0; + //Get and check pe header mem.mem = rva_to_va(mapview, mem.dos->e_lfanew); - if(IsBadReadPtr(mem.pe, sizeof(*mem.pe)) || mem.pe->Signature != IMAGE_NT_SIGNATURE) - return(0); - - return(mem.pe); + if (IsBadReadPtr(mem.pe, sizeof(*mem.pe)) || mem.pe->Signature != IMAGE_NT_SIGNATURE) + return 0; + + return mem.pe; } // Returns export table for valid module -static IMAGE_EXPORT_DIRECTORY * DLLINTERNAL_NOVIS get_export_table(void * mapview, IMAGE_NT_HEADERS * ntheaders, IMAGE_SECTION_HEADER * sections, int num_sects) { - union { +IMAGE_EXPORT_DIRECTORY *get_export_table(void * mapview, IMAGE_NT_HEADERS * ntheaders, IMAGE_SECTION_HEADER * sections, int num_sects) { + union { unsigned long mem; void * pvoid; IMAGE_DOS_HEADER * dos; IMAGE_NT_HEADERS * pe; IMAGE_EXPORT_DIRECTORY * export_dir; } mem; - + mem.pe = ntheaders; - + //Check for exports - if(!mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) - return(0); - + if (!mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) + return 0; + mem.mem = va_to_mapaddr(mapview, sections, num_sects, mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - if(IsBadReadPtr(mem.export_dir, sizeof(*mem.export_dir))) - return(0); - - return(mem.export_dir); + if (IsBadReadPtr(mem.export_dir, sizeof(*mem.export_dir))) + return 0; + + return mem.export_dir; } -mBOOL DLLINTERNAL is_gamedll(const char *filename) { +mBOOL is_gamedll(const char *filename) { HANDLE hFile; HANDLE hMap; void * mapview; @@ -78,116 +75,119 @@ mBOOL DLLINTERNAL is_gamedll(const char *filename) { // Try open file for read hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if(is_invalid_handle(hFile)) { + if (is_invalid_handle(hFile)) { META_DEBUG(3, ("is_gamedll(%s): CreateFile() failed.", filename)); - return(mFALSE); + return mFALSE; } - + // hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if(is_invalid_handle(hMap)) { + if (is_invalid_handle(hMap)) { META_DEBUG(3, ("is_gamedll(%s): CreateFileMapping() failed.", filename)); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - + // mapview = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); - if(!mapview) { + if (!mapview) { META_DEBUG(3, ("is_gamedll(%s): MapViewOfFile() failed.", filename)); CloseHandle(hMap); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - + ntheaders = get_ntheaders(mapview); - if(!ntheaders) { + if (!ntheaders) { META_DEBUG(3, ("is_gamedll(%s): get_ntheaders() failed.", filename)); UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - + //Sections for va_to_mapaddr function sections = IMAGE_FIRST_SECTION(ntheaders); num_sects = ntheaders->FileHeader.NumberOfSections; - if(IsBadReadPtr(sections, num_sects * sizeof(IMAGE_SECTION_HEADER))) { + if (IsBadReadPtr(sections, num_sects * sizeof(IMAGE_SECTION_HEADER))) { META_DEBUG(3, ("is_gamedll(%s): IMAGE_FIRST_SECTION() failed.", filename)); UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - + // exports = get_export_table(mapview, ntheaders, sections, num_sects); - if(!exports) { + if (!exports) { META_DEBUG(3, ("is_gamedll(%s): get_export_table() failed.", filename)); UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - + // unsigned long * names = (unsigned long *)va_to_mapaddr(mapview, sections, num_sects, exports->AddressOfNames); - if(IsBadReadPtr(names, exports->NumberOfNames * sizeof(unsigned long))) { + if (IsBadReadPtr(names, exports->NumberOfNames * sizeof(unsigned long))) + { META_DEBUG(3, ("is_gamedll(%s): Pointer to exported function names is invalid.", filename)); UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - return(mFALSE); + return mFALSE; } - - for(unsigned int i = 0; i < exports->NumberOfNames; i++) { + + for (unsigned int i = 0; i < exports->NumberOfNames; i++) + { //get function name with valid address char * funcname = (char *)va_to_mapaddr(mapview, sections, num_sects, names[i]); - if(IsBadStringPtrA(funcname, 128)) + if (IsBadStringPtrA(funcname, 128)) continue; - + // Check // Fast check for 'G' first - if(funcname[0] == 'G') { + if (funcname[0] == 'G') + { // Collect export information - if(!has_GiveFnptrsToDll) - has_GiveFnptrsToDll = strmatch(funcname, "GiveFnptrsToDll"); - if(!has_GetEntityAPI2) - has_GetEntityAPI2 = strmatch(funcname, "GetEntityAPI2"); - if(!has_GetEntityAPI) - has_GetEntityAPI = strmatch(funcname, "GetEntityAPI"); + if (!has_GiveFnptrsToDll) + has_GiveFnptrsToDll = !Q_strcmp(funcname, "GiveFnptrsToDll"); + if (!has_GetEntityAPI2) + has_GetEntityAPI2 = !Q_strcmp(funcname, "GetEntityAPI2"); + if (!has_GetEntityAPI) + has_GetEntityAPI = !Q_strcmp(funcname, "GetEntityAPI"); } // Check if metamod plugin - else if(funcname[0] == 'M') { - if(strmatch(funcname, "Meta_Init") || - strmatch(funcname, "Meta_Query") || - strmatch(funcname, "Meta_Attach") || - strmatch(funcname, "Meta_Detach")) { + else if (funcname[0] == 'M') + { + if (!Q_strcmp(funcname, "Meta_Init") || !Q_strcmp(funcname, "Meta_Query") || !Q_strcmp(funcname, "Meta_Attach") || !Q_strcmp(funcname, "Meta_Detach")) + { // Metamod plugin.. is not gamedll META_DEBUG(5, ("is_gamedll(%s): Detected Metamod plugin, library exports [%s].", filename, funcname)); - + UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - - return(mFALSE); + + return mFALSE; } } } - + UnmapViewOfFile(mapview); CloseHandle(hMap); CloseHandle(hFile); - + // Check if gamedll - if(has_GiveFnptrsToDll && (has_GetEntityAPI2 || has_GetEntityAPI)) { + if (has_GiveFnptrsToDll && (has_GetEntityAPI2 || has_GetEntityAPI)) + { // This is gamedll! META_DEBUG(5, ("is_gamedll(%s): Detected GameDLL.", filename)); - - return(mTRUE); - } else { + return mTRUE; + } + else + { META_DEBUG(5, ("is_gamedll(%s): Library isn't GameDLL.", filename)); - - return(mFALSE); + return mFALSE; } } diff --git a/src/osdep_linkent_linux.cpp b/metamod/src/osdep_linkent_linux.cpp similarity index 53% rename from src/osdep_linkent_linux.cpp rename to metamod/src/osdep_linkent_linux.cpp index 32c7bb6..e901e27 100644 --- a/src/osdep_linkent_linux.cpp +++ b/metamod/src/osdep_linkent_linux.cpp @@ -17,103 +17,93 @@ #include "log_meta.h" // META_LOG, etc #include "support_meta.h" -// // Linux code for dynamic linkents -// -- by Jussi Kivilinna -// +// opcode, e9, + sizeof pointer +#define BYTES_SIZE (1 + sizeof(void *)) -//opcode, e9, + sizeof pointer -#define BYTES_SIZE (1 + sizeof(void*)) +typedef void *(*dlsym_func)(void *module, const char *funcname); -typedef void * (*dlsym_func)(void * module, const char * funcname); +static void *gamedll_module_handle = 0; +static void *metamod_module_handle = 0; -static void * gamedll_module_handle = 0; -static void * metamod_module_handle = 0; - -//pointer to original dlsym +// pointer to original dlsym static dlsym_func dlsym_original; -//contains jmp to replacement_dlsym @dlsym_original +// contains jmp to replacement_dlsym @dlsym_original static unsigned char dlsym_new_bytes[BYTES_SIZE]; -//contains original bytes of dlsym +// contains original bytes of dlsym static unsigned char dlsym_old_bytes[BYTES_SIZE]; -//Mutex for our protection +// Mutex for our protection static pthread_mutex_t mutex_replacement_dlsym = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -//constructs new jmp forwarder -inline void construct_jmp_instruction(void *x, void *place, void* target) +// constructs new jmp forwarder +inline void construct_jmp_instruction(void *x, void *place, void *target) { ((unsigned char *)x)[0] = 0xe9; *(unsigned long *)((char *)x + 1) = (unsigned long)target - ((unsigned long)place + 5); } -//checks if pointer x points to jump forwarder -inline bool is_code_trampoline_jmp_opcode(void *x) -{ - return (((unsigned char *)x)[0] == 0xff || ((unsigned char *)x)[1] == 0x25); -} - -//extracts pointer from "jmp dword ptr[pointer]" -inline void * extract_function_pointer_from_trampoline_jmp(void *x) +// checks if pointer x points to jump forwarder +inline bool is_code_trampoline_jmp_opcode(void *x) { - return (**(void***)((char *)(x) + 2)); + return (((unsigned char *)x)[0] == 0xff || ((unsigned char *)x)[1] == 0x25); +} + +// extracts pointer from "jmp dword ptr[pointer]" +inline void *extract_function_pointer_from_trampoline_jmp(void *x) +{ + return (**(void ***)((char *)(x) + 2)); } -// //restores old dlsym -// -inline void DLLINTERNAL restore_original_dlsym(void) +inline void restore_original_dlsym() { //Copy old dlsym bytes back - Q_memcpy((void*)dlsym_original, dlsym_old_bytes, BYTES_SIZE); + Q_memcpy((void *)dlsym_original, dlsym_old_bytes, BYTES_SIZE); } -// //resets new dlsym -// -inline void DLLINTERNAL reset_dlsym_hook(void) +inline void reset_dlsym_hook() { //Copy new dlsym bytes back - Q_memcpy((void*)dlsym_original, dlsym_new_bytes, BYTES_SIZE); + Q_memcpy((void *)dlsym_original, dlsym_new_bytes, BYTES_SIZE); } -// // Replacement dlsym function -// -static void * __replacement_dlsym(void * module, const char * funcname) +static void *__replacement_dlsym(void *module, const char *funcname) { //these are needed in case dlsym calls dlsym, default one doesn't do //it but some LD_PRELOADed library that hooks dlsym might actually //do so. static int is_original_restored = 0; int was_original_restored = is_original_restored; - + //Lock before modifing original dlsym pthread_mutex_lock(&mutex_replacement_dlsym); - + //restore old dlsym - if(!is_original_restored) + if (!is_original_restored) { restore_original_dlsym(); - + is_original_restored = 1; } - + //check if we should hook this call - if(module != metamod_module_handle || !metamod_module_handle || !gamedll_module_handle) + if (module != metamod_module_handle || !metamod_module_handle || !gamedll_module_handle) { //no metamod/gamedll module? should we remove hook now? - void * retval = dlsym_original(module, funcname); - - if(metamod_module_handle && gamedll_module_handle) + void *retval = dlsym_original(module, funcname); + + if (metamod_module_handle && gamedll_module_handle) { - if(!was_original_restored) + if (!was_original_restored) { //reset dlsym hook reset_dlsym_hook(); - + is_original_restored = 0; } } @@ -121,83 +111,81 @@ static void * __replacement_dlsym(void * module, const char * funcname) { //no metamod/gamedll module? should we remove hook now by not reseting it back? } - + //unlock pthread_mutex_unlock(&mutex_replacement_dlsym); - - return(retval); + + return retval; } - + //dlsym on metamod module - void * func = dlsym_original(module, funcname); - - if(!func) + void *func = dlsym_original(module, funcname); + + if (!func) { //function not in metamod module, try gamedll func = dlsym_original(gamedll_module_handle, funcname); } - - if(!was_original_restored) + + if (!was_original_restored) { //reset dlsym hook reset_dlsym_hook(); - + is_original_restored = 0; } - + //unlock pthread_mutex_unlock(&mutex_replacement_dlsym); - - return(func); + return func; } -// // Initialize -// -int DLLINTERNAL init_linkent_replacement(DLHANDLE MetamodHandle, DLHANDLE GameDllHandle) +int init_linkent_replacement(DLHANDLE MetamodHandle, DLHANDLE GameDllHandle) { metamod_module_handle = MetamodHandle; gamedll_module_handle = GameDllHandle; - + // dlsym is already known to be pointing to valid function, we loaded gamedll using it earlier! - void * sym_ptr = (void*)&dlsym; - while(is_code_trampoline_jmp_opcode(sym_ptr)) { + void *sym_ptr = (void*)&dlsym; + while (is_code_trampoline_jmp_opcode(sym_ptr)) + { sym_ptr = extract_function_pointer_from_trampoline_jmp(sym_ptr); } - + dlsym_original = (dlsym_func)sym_ptr; - - //Backup old bytes of "dlsym" function - Q_memcpy(dlsym_old_bytes, (void*)dlsym_original, BYTES_SIZE); - - //Construct new bytes: "jmp offset[replacement_sendto] @ sendto_original" - construct_jmp_instruction((void*)&dlsym_new_bytes[0], (void*)dlsym_original, (void*)&__replacement_dlsym); - - //Check if bytes overlap page border. + + // Backup old bytes of "dlsym" function + Q_memcpy(dlsym_old_bytes, (void *)dlsym_original, BYTES_SIZE); + + // Construct new bytes: "jmp offset[replacement_sendto] @ sendto_original" + construct_jmp_instruction((void *)&dlsym_new_bytes[0], (void *)dlsym_original, (void *)&__replacement_dlsym); + + // Check if bytes overlap page border. unsigned long start_of_page = PAGE_ALIGN((long)dlsym_original) - PAGE_SIZE; unsigned long size_of_pages = 0; - - if((unsigned long)dlsym_original + BYTES_SIZE > PAGE_ALIGN((unsigned long)dlsym_original)) + + if ((unsigned long)dlsym_original + BYTES_SIZE > PAGE_ALIGN((unsigned long)dlsym_original)) { - //bytes are located on two pages + // bytes are located on two pages size_of_pages = PAGE_SIZE*2; } else { - //bytes are located entirely on one page. + // bytes are located entirely on one page. size_of_pages = PAGE_SIZE; } - - //Remove PROT_READ restriction - if(mprotect((void*)start_of_page, size_of_pages, PROT_READ|PROT_WRITE|PROT_EXEC)) + + // Remove PROT_READ restriction + if (mprotect((void*)start_of_page, size_of_pages, PROT_READ|PROT_WRITE|PROT_EXEC)) { META_ERROR("Couldn't initialize dynamic linkents, mprotect failed: %i. Exiting...", errno); - return(0); + return 0; } - - //Write our own jmp-forwarder on "dlsym" + + // Write our own jmp-forwarder on "dlsym" reset_dlsym_hook(); - - //done - return(1); + + // done + return 1; } diff --git a/metamod/src/osdep_linkent_win32.cpp b/metamod/src/osdep_linkent_win32.cpp new file mode 100644 index 0000000..8b93d14 --- /dev/null +++ b/metamod/src/osdep_linkent_win32.cpp @@ -0,0 +1,191 @@ +#include "precompiled.h" + +// Reads metamod.dll and game.dll function export tables and combines theim to +// single table that replaces metamod.dll's original table. +typedef struct sort_names_s { + unsigned long name; + unsigned short nameOrdinal; +} sort_names_t; + +#define rva_to_va(base, rva) ((unsigned long)base + (unsigned long)rva) // relative virtual address to virtual address +#define va_to_rva(base, va) ((unsigned long)va - (unsigned long)base) // virtual address to relative virtual address + +// Checks module signatures and return ntheaders pointer for valid module +IMAGE_NT_HEADERS *get_ntheaders(HMODULE module) +{ + union { + unsigned long mem; + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *pe; + } mem; + + // Check if valid dos header + mem.mem = (unsigned long)module; + if (IsBadReadPtr(mem.dos, sizeof(*mem.dos)) || mem.dos->e_magic != IMAGE_DOS_SIGNATURE) + return nullptr; + + // Get and check pe header + mem.mem = rva_to_va(module, mem.dos->e_lfanew); + if (IsBadReadPtr(mem.pe, sizeof(*mem.pe)) || mem.pe->Signature != IMAGE_NT_SIGNATURE) + return nullptr; + + return mem.pe; +} + +// Returns export table for valid module +IMAGE_EXPORT_DIRECTORY *get_export_table(HMODULE module) +{ + union { + unsigned long mem; + void *pvoid; + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS *pe; + IMAGE_EXPORT_DIRECTORY *export_dir; + } mem; + + // check module + mem.pe = get_ntheaders(module); + if (!mem.pe) + return nullptr; + + // check for exports + if (!mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) + return nullptr; + + mem.mem = rva_to_va(module, mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + if (IsBadReadPtr(mem.export_dir, sizeof(*mem.export_dir))) + return nullptr; + + return mem.export_dir; +} + +// Sort function for qsort +int sort_names_list(const sort_names_t *A, const sort_names_t *B) +{ + const char *str_A = (const char *)A->name; + const char *str_B = (const char *)B->name; + + return Q_strcmp(str_A, str_B); +} + +// Combines moduleMM and moduleGame export tables and replaces moduleMM table with new one +int combine_module_export_tables(HMODULE moduleMM, HMODULE moduleGame) +{ + IMAGE_EXPORT_DIRECTORY *exportMM; + IMAGE_EXPORT_DIRECTORY *exportGame; + + unsigned long newNumberOfFunctions; + unsigned long newNumberOfNames; + unsigned long *newFunctions; + unsigned long *newNames; + unsigned short *newNameOrdinals; + sort_names_t *newSort; + + unsigned long i; + unsigned long u; + unsigned long funcCount; + unsigned long nameCount; + unsigned long listFix; + + // get export tables + exportMM = get_export_table(moduleMM); + exportGame = get_export_table(moduleGame); + if (!exportMM || !exportGame) + { + META_ERROR("Couldn't initialize dynamic linkents, exportMM: %i, exportGame: %i. Exiting...", exportMM, exportGame); + return 0; + } + + // setup new export table + newNumberOfFunctions = exportMM->NumberOfFunctions + exportGame->NumberOfFunctions; + newNumberOfNames = exportMM->NumberOfNames + exportGame->NumberOfNames; + + // alloc lists + *(void**)&newFunctions = calloc(1, newNumberOfFunctions * sizeof(*newFunctions)); + *(void**)&newSort = calloc(1, newNumberOfNames * sizeof(*newSort)); + + // copy moduleMM to new export + for (funcCount = 0; funcCount < exportMM->NumberOfFunctions; funcCount++) + newFunctions[funcCount] = rva_to_va(moduleMM, ((unsigned long*)rva_to_va(moduleMM, exportMM->AddressOfFunctions))[funcCount]); + for (nameCount = 0; nameCount < exportMM->NumberOfNames; nameCount++) + { + //fix name address + newSort[nameCount].name = rva_to_va(moduleMM, ((unsigned long*)rva_to_va(moduleMM, exportMM->AddressOfNames))[nameCount]); + //ordinal is index to function list + newSort[nameCount].nameOrdinal = ((unsigned short *)rva_to_va(moduleMM, exportMM->AddressOfNameOrdinals))[nameCount]; + } + + // copy moduleGame to new export + for (i = 0; i < exportGame->NumberOfFunctions; i++) + newFunctions[funcCount + i] = rva_to_va(moduleGame, ((unsigned long*)rva_to_va(moduleGame, exportGame->AddressOfFunctions))[i]); + for (i = 0, listFix = 0; i < exportGame->NumberOfNames; i++) + { + const char *name = (const char *)rva_to_va(moduleGame, ((unsigned long*)rva_to_va(moduleGame, exportGame->AddressOfNames))[i]); + // check if name already in the list + for (u = 0; u < nameCount; u++) + { + if (!strcasecmp(name, (const char*)newSort[u].name)) + { + listFix -= 1; + break; + } + } + + // already in the list.. skip + if (u < nameCount) + continue; + + newSort[nameCount + i + listFix].name = (unsigned long)name; + newSort[nameCount + i + listFix].nameOrdinal = (unsigned short)funcCount + ((unsigned short *)rva_to_va(moduleGame, exportGame->AddressOfNameOrdinals))[i]; + } + + // set new number + newNumberOfNames = nameCount + i + listFix; + + // sort names list + qsort(newSort, newNumberOfNames, sizeof(*newSort), (int(*)(const void*, const void*))&sort_names_list); + + // make newNames and newNameOrdinals lists (VirtualAlloc so we dont waste heap memory to stuff that isn't freed) + *(void**)&newNames = VirtualAlloc(0, newNumberOfNames * sizeof(*newNames), MEM_COMMIT, PAGE_READWRITE); + *(void**)&newNameOrdinals = VirtualAlloc(0, newNumberOfNames * sizeof(*newNameOrdinals), MEM_COMMIT, PAGE_READWRITE); + + for (i = 0; i < newNumberOfNames; i++) + { + newNames[i] = newSort[i].name; + newNameOrdinals[i] = newSort[i].nameOrdinal; + } + + free(newSort); + + //translate VAs to RVAs + for (i = 0; i < newNumberOfFunctions; i++) + newFunctions[i] = va_to_rva(moduleMM, newFunctions[i]); + + for (i = 0; i < newNumberOfNames; i++) + { + newNames[i] = va_to_rva(moduleMM, newNames[i]); + newNameOrdinals[i] = (unsigned short)va_to_rva(moduleMM, newNameOrdinals[i]); + } + + DWORD OldProtect; + if (!VirtualProtect(exportMM, sizeof(*exportMM), PAGE_READWRITE, &OldProtect)) + { + META_ERROR("Couldn't initialize dynamic linkents, VirtualProtect failed: %i. Exiting...", GetLastError()); + return 0; + } + + exportMM->Base = 1; + exportMM->NumberOfFunctions = newNumberOfFunctions; + exportMM->NumberOfNames = newNumberOfNames; + *(unsigned long*)&(exportMM->AddressOfFunctions) = va_to_rva(moduleMM, newFunctions); + *(unsigned long*)&(exportMM->AddressOfNames) = va_to_rva(moduleMM, newNames); + *(unsigned long*)&(exportMM->AddressOfNameOrdinals) = va_to_rva(moduleMM, newNameOrdinals); + + VirtualProtect(exportMM, sizeof(*exportMM), OldProtect, &OldProtect); + return 1; +} + +int init_linkent_replacement(DLHANDLE moduleMetamod, DLHANDLE moduleGame) +{ + return combine_module_export_tables(moduleMetamod, moduleGame); +} diff --git a/metamod/src/osdep_p.cpp b/metamod/src/osdep_p.cpp new file mode 100644 index 0000000..47962cd --- /dev/null +++ b/metamod/src/osdep_p.cpp @@ -0,0 +1,84 @@ +#include "precompiled.h" + +#ifdef _WIN32 +// MSVC doesn't provide "dirent.h" header. These functions wrap opendir/readdir/closedir +// functions to FindFirst/FindNext/FindClose win32api-functions. +DIR *my_opendir(const char *path) +{ + char search_path[MAX_PATH]; + DIR *dir; + + // Add wildcards to path + safevoid_snprintf(search_path, sizeof(search_path), "%s\\*.*", path); + + // Get memory for new DIR object + dir = (DIR *)calloc(1, sizeof(DIR)); + + // Start searching + dir->handle = FindFirstFileA(search_path, &dir->find_data); + if (dir->handle == INVALID_HANDLE_VALUE) + { + free(dir); + return nullptr; + } + + // Found file + dir->not_found = 0; + return dir; +} + +struct dirent *my_readdir(DIR *dir) +{ + // If not found stop + if (!dir || dir->not_found) + return nullptr; + + // Set filename + Q_strncpy(dir->ent.d_name, dir->find_data.cFileName, sizeof(dir->ent.d_name) - 1); + dir->ent.d_name[sizeof(dir->ent.d_name) - 1] = '\0'; + + // Search next + dir->not_found = !FindNextFileA(dir->handle, &dir->find_data); + return &dir->ent; +} + +void my_closedir(DIR *dir) +{ + if (!dir) + return; + + FindClose(dir->handle); + free(dir); +} + +#endif // _WIN32 + +// get module handle of memptr +#ifdef _WIN32 +DLHANDLE get_module_handle_of_memptr(void *memptr) +{ + MEMORY_BASIC_INFORMATION MBI; + + if (!VirtualQuery(memptr, &MBI, sizeof(MBI))) + return nullptr; + + if (MBI.State != MEM_COMMIT) + return nullptr; + + if (!MBI.AllocationBase) + return nullptr; + + return (DLHANDLE)MBI.AllocationBase; +} +#else +DLHANDLE get_module_handle_of_memptr(void *memptr) +{ + Dl_info dli; + Q_memset(&dli, 0, sizeof(dli)); + + if (dladdr(memptr, &dli)) + return dlopen(dli.dli_fname, RTLD_NOW); + else + return (void*)0; +} +#endif diff --git a/metamod/src/osdep_p.h b/metamod/src/osdep_p.h new file mode 100644 index 0000000..06ad417 --- /dev/null +++ b/metamod/src/osdep_p.h @@ -0,0 +1,33 @@ +#pragma once + +#include "types_meta.h" // mBOOL +#include "osdep.h" // PATH_MAX + +// Checks if file is hlsdk api game dll (osdep_detect_gamedll_linux.cpp and osdep_detect_gamedll_win32.cpp) +mBOOL is_gamedll(const char *filename); + +// MSVC doesn't provide opendir/readdir/closedir, so we write our own. +#ifdef _WIN32 + struct my_dirent { + char d_name[PATH_MAX]; + }; + typedef struct { + HANDLE handle; + WIN32_FIND_DATAA find_data; + struct my_dirent ent; + int not_found; + } my_DIR; + + #define dirent my_dirent + #define DIR my_DIR + + DIR *my_opendir(const char *); + struct dirent *my_readdir(DIR *); + void my_closedir(DIR *); + + #define opendir(x) my_opendir(x) + #define readdir(x) my_readdir(x) + #define closedir(x) my_closedir(x) +#endif // _WIN32 + +DLHANDLE get_module_handle_of_memptr(void *memptr); diff --git a/src/plinfo.h b/metamod/src/plinfo.h similarity index 97% rename from src/plinfo.h rename to metamod/src/plinfo.h index b6697fb..4e70ec6 100644 --- a/src/plinfo.h +++ b/metamod/src/plinfo.h @@ -40,7 +40,8 @@ typedef struct { PLUG_LOADTIME loadable; // when loadable PLUG_LOADTIME unloadable; // when unloadable } plugin_info_t; -extern plugin_info_t Plugin_info DLLHIDDEN; + +extern plugin_info_t Plugin_info; // Plugin identifier, passed to all Meta Utility Functions. typedef plugin_info_t* plid_t; diff --git a/metamod/src/precompiled.cpp b/metamod/src/precompiled.cpp new file mode 100644 index 0000000..5f656a4 --- /dev/null +++ b/metamod/src/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/metamod/src/precompiled.h b/metamod/src/precompiled.h new file mode 100644 index 0000000..0cdfb7d --- /dev/null +++ b/metamod/src/precompiled.h @@ -0,0 +1,59 @@ +#pragma once + +#include "version/appversion.h" + +#include +#include +#include +#include // for strncpy(), etc + +#include +#include + +#include "osconfig.h" +#include "h_export.h" + +#include "osdep.h" // win32 vsnprintf, etc +#include "sdk_util.h" + +#include "eiface.h" // engfuncs_t, globalvars_t +#include "meta_api.h" // meta_globals_t, etc + +#include "linkent.h" // LINK_ENTITY_TO_PLUGIN + +#include "ret_type.h" +#include "types_meta.h" +#include "api_info.h" +#include "api_hook.h" +#include "mplugin.h" +#include "metamod.h" + +#include "commands_meta.h" // me +#include "log_meta.h" // META_CONS, etc + +#include "conf_meta.h" // me +#include "support_meta.h" // strmatch + + +// #include // alloca, etc ?????????? + + + // Don't include winspool.h; clashes with SERVER_EXECUTE from engine +// #define _WINSPOOL_H +// #include +// #include // Header structures + + +#include "osdep_p.h" // is_gamedll, ... +#include "game_support.h" // lookup_game, etc +#include "reg_support.h" // meta_AddServerCommand, etc +#include "mm_pextensions.h" + + + + + + + + + diff --git a/src/reg_support.cpp b/metamod/src/reg_support.cpp similarity index 79% rename from src/reg_support.cpp rename to metamod/src/reg_support.cpp index ca29a8e..1bce99f 100644 --- a/src/reg_support.cpp +++ b/metamod/src/reg_support.cpp @@ -1,16 +1,4 @@ -#ifdef linux -// enable extra routines in system header files, like strsignal -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#endif /* linux */ - -#include // strsignal, etc -#include // always -#include "sdk_util.h" // REG_SVR_COMMAND, etc -#include "reg_support.h" // me -#include "metamod.h" // RegCmds, g_Players, etc -#include "log_meta.h" // META_ERROR, etc +#include "precompiled.h" // "Register" support. // @@ -47,29 +35,33 @@ // from the console that they no longer have an effect. // // Also note, the console commands for listing registered cmds and cvars -// will try to show the name of the associated plugin. +// will try to show the name of the associated plugin. // Generic command handler, passed to the engine for any AddServerCommand // calls made by the plugin. It finds the appropriate plugin function // pointer to call based on CMD_ARGV(0). -void DLLHIDDEN meta_command_handler(void) { +void meta_command_handler() +{ MRegCmd *icmd; const char *cmd; META_DEBUG(5, ("called: meta_command_handler; arg0=%s args='%s'", CMD_ARGV(0), CMD_ARGS())); - cmd=CMD_ARGV(0); - if(!cmd) { + cmd = CMD_ARGV(0); + if (!cmd) + { META_WARNING("Null command name in meta_command_handler() ??"); return; } - icmd=RegCmds->find(cmd); - if(!icmd) { + icmd = RegCmds->find(cmd); + if (!icmd) + { META_WARNING("Couldn't find registered plugin command: %s", cmd); return; } - if(icmd->call() != mTRUE) + + if (icmd->call() != mTRUE) META_CONS("[metamod: command '%s' unavailable; plugin unloaded]", cmd); } @@ -83,25 +75,26 @@ void DLLHIDDEN meta_command_handler(void) { // The string handed to the engine is just a strdup() of the plugin's // string. The function pointer handed to the engine is actually a pointer // to a generic command-handler function (see above). -void DLLHIDDEN meta_AddServerCommand(const char *cmd_name, void (*function) (void)) { - MPlugin *iplug=NULL; +void meta_AddServerCommand(char *cmd_name, void (*function)()) +{ + MPlugin *iplug=NULL; MRegCmd *icmd=NULL; META_DEBUG(4, ("called: meta_AddServerCommand; cmd_name=%s, function=%d", cmd_name, function)); // try to find which plugin is registering this command - if(!(iplug=Plugins->find_memloc((void *)function))) { + if (!(iplug=Plugins->find_memloc((void *)function))) { // if this isn't supported on this OS, don't log an error - if(meta_errno != ME_OSNOTSUP) + if (meta_errno != ME_OSNOTSUP) META_WARNING("Failed to find memloc for regcmd '%s'", cmd_name); } // See if this command was previously registered, ie a "reloaded" plugin. icmd=RegCmds->find(cmd_name); - if(!icmd) { + if (!icmd) { // If not found, add. icmd=RegCmds->add(cmd_name); - if(!icmd) { + if (!icmd) { // error details logged in add() return; } @@ -113,7 +106,7 @@ void DLLHIDDEN meta_AddServerCommand(const char *cmd_name, void (*function) (voi icmd->status=RG_VALID; // Store which plugin this is for, if we know. We can use '0' for // unknown plugin, since plugin index starts at 1. - if(iplug) + if (iplug) icmd->plugid = iplug->index; else icmd->plugid = 0; @@ -132,32 +125,38 @@ void DLLHIDDEN meta_AddServerCommand(const char *cmd_name, void (*function) (voi // values via the engine functions, this will work fine. If the plugin // code tries to _directly_ read/set the fields of its own cvar structures, // it will fail to work properly. -void DLLHIDDEN meta_CVarRegister(cvar_t *pCvar) { - MPlugin *iplug=NULL; - MRegCvar *icvar=NULL; +void meta_CVarRegister(cvar_t *pCvar) +{ + MPlugin *iplug = nullptr; + MRegCvar *icvar = nullptr; META_DEBUG(4, ("called: meta_CVarRegister; name=%s", pCvar->name)); // try to find which plugin is registering this cvar - if(!(iplug=Plugins->find_memloc((void *)pCvar))) { + if (!(iplug = Plugins->find_memloc((void *)pCvar))) + { // if this isn't supported on this OS, don't log an error - if(meta_errno != ME_OSNOTSUP) + if (meta_errno != ME_OSNOTSUP) + { // Note: if cvar_t was malloc'd by the plugin, we can't // determine the calling plugin. Thus, this becomes a Debug // rather than Error message. - META_DEBUG(1, ("Failed to find memloc for regcvar '%s'", - pCvar->name)); + META_DEBUG(1, ("Failed to find memloc for regcvar '%s'", pCvar->name)); + } } // See if this cvar was previously registered, ie a "reloaded" plugin. - icvar=RegCvars->find(pCvar->name); - if(!icvar) { + icvar = RegCvars->find(pCvar->name); + if (!icvar) + { // If not found, add. - icvar=RegCvars->add(pCvar->name); - if(!icvar) { + icvar = RegCvars->add(pCvar->name); + if (!icvar) + { // error details logged in add() return; } + // Reset to given value icvar->set(pCvar); CVAR_REGISTER(icvar->data); @@ -165,23 +164,23 @@ void DLLHIDDEN meta_CVarRegister(cvar_t *pCvar) { // Note: if not a new cvar, then we don't set the values, and just keep // the pre-existing value. - icvar->status=RG_VALID; + icvar->status = RG_VALID; + // Store which plugin this is for, if we know. Use '0' for unknown // plugin, as plugin index starts at 1. - if(iplug) + if (iplug) icvar->plugid = iplug->index; else icvar->plugid = 0; } - -// Replacement for engine routine RegUserMsg; called by plugins. -int DLLHIDDEN meta_RegUserMsg(const char *pszName, int iSize) { - return(REG_USER_MSG(strdup(pszName), iSize)); +// Replacement for engine routine RegUserMsg; called by plugins. +int meta_RegUserMsg(const char *pszName, int iSize) { + return REG_USER_MSG(strdup(pszName), iSize); } // Intercept and record queries -void DLLHIDDEN meta_QueryClientCvarValue(const edict_t *player, const char *cvarName) +void meta_QueryClientCvarValue(const edict_t *player, const char *cvarName) { g_Players.set_player_cvar_query(player, cvarName); (*g_engfuncs.pfnQueryClientCvarValue)(player, cvarName); diff --git a/metamod/src/reg_support.h b/metamod/src/reg_support.h new file mode 100644 index 0000000..317ae1f --- /dev/null +++ b/metamod/src/reg_support.h @@ -0,0 +1,10 @@ +#pragma once + +#include "mreg.h" // REG_CMD_FN, etc + +// these are only 'hidden' because called from outside (plugins and engine) +void meta_command_handler(); +void meta_AddServerCommand(char *cmd_name, REG_CMD_FN function); +void meta_CVarRegister(cvar_t *pCvar); +int meta_RegUserMsg(const char *pszName, int iSize); +void meta_QueryClientCvarValue(const edict_t *player, const char *cvarName); diff --git a/src/ret_type.h b/metamod/src/ret_type.h similarity index 72% rename from src/ret_type.h rename to metamod/src/ret_type.h index f44872a..aca85f2 100644 --- a/src/ret_type.h +++ b/metamod/src/ret_type.h @@ -1,12 +1,11 @@ -#ifndef RET_TYPE_H -#define RET_TYPE_H +#pragma once #include "new_baseclass.h" -class class_ret_t : public class_metamod_new { +class class_ret_t: public class_metamod_new { public: // Construction - inline class_ret_t(void) { }; + inline class_ret_t() { }; inline class_ret_t(float f) { data.f = f; }; inline class_ret_t(void * p) { data.p = p; }; inline class_ret_t(const char * pc) { data.pc = pc; }; @@ -17,23 +16,22 @@ public: inline class_ret_t(unsigned long ui) { data.ui = ui; }; inline class_ret_t(unsigned short us) { data.ui = us; }; inline class_ret_t(unsigned char uc) { data.ui = uc; }; - + // Reading/Writing - inline void * getptr(void) { return(&data); }; - + inline void *getptr() { return &data; }; + #define SET_RET_CLASS(ret,type,x) \ *(type*)((ret).getptr()) = (type)(x) #define GET_RET_CLASS(ret,type) \ (*(type*)((ret).getptr())) private: - //Data (select data size of largest type) (x86: 32bit, x86_64: 64bit) - union { - void * p; - const char * pc; + // Data (select data size of largest type) (x86: 32bit, x86_64: 64bit) + union + { + void *p; + const char *pc; float f; long i; unsigned long ui; } data; }; - -#endif /*RET_TYPE_H*/ diff --git a/metamod/src/sdk_util.cpp b/metamod/src/sdk_util.cpp new file mode 100644 index 0000000..4582d1d --- /dev/null +++ b/metamod/src/sdk_util.cpp @@ -0,0 +1,77 @@ +#include "precompiled.h" + +const char *META_UTIL_VarArgs(const char *format, ...) +{ + va_list argptr; + static char string[4096]; + + va_start(argptr, format); + safevoid_vsnprintf(string, sizeof(string), format, argptr); + va_end(argptr); + + return string; +} + +short FixedSigned16(float value, float scale) +{ + int output = (int)(value * scale); + if (output > 32767) + output = 32767; + + if (output < -32768) + output = -32768; + + return (short)output; +} + +unsigned short FixedUnsigned16(float value, float scale) +{ + int output = (int)(value * scale); + if (output < 0) + output = 0; + + if (output > 0xFFFF) + output = 0xFFFF; + + return (unsigned short)output; +} + +void META_UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage) +{ + if (fast_FNullEnt(pEntity) || pEntity->free) + { + return; + } + + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + WRITE_BYTE(TE_TEXTMESSAGE); + WRITE_BYTE(textparms.channel & 0xFF); + WRITE_SHORT(FixedSigned16(textparms.x, 1<<13)); + WRITE_SHORT(FixedSigned16(textparms.y, 1<<13)); + WRITE_BYTE(textparms.effect); + WRITE_BYTE(textparms.r1); + WRITE_BYTE(textparms.g1); + WRITE_BYTE(textparms.b1); + WRITE_BYTE(textparms.a1); + WRITE_BYTE(textparms.r2); + WRITE_BYTE(textparms.g2); + WRITE_BYTE(textparms.b2); + WRITE_BYTE(textparms.a2); + WRITE_SHORT(FixedUnsigned16(textparms.fadeinTime, 1<<8)); + WRITE_SHORT(FixedUnsigned16(textparms.fadeoutTime, 1<<8)); + WRITE_SHORT(FixedUnsigned16(textparms.holdTime, 1<<8)); + if (textparms.effect == 2) + { + WRITE_SHORT(FixedUnsigned16(textparms.fxTime, 1 << 8)); + } + if (Q_strlen(pMessage) < 512) + { + WRITE_STRING(pMessage); + } else { + char tmp[512]; + Q_strncpy(tmp, pMessage, 511); + tmp[511] = 0; + WRITE_STRING(tmp); + } + MESSAGE_END(); +} diff --git a/src/sdk_util.h b/metamod/src/sdk_util.h similarity index 52% rename from src/sdk_util.h rename to metamod/src/sdk_util.h index bc195a0..b9b5193 100644 --- a/src/sdk_util.h +++ b/metamod/src/sdk_util.h @@ -1,8 +1,4 @@ -// Wrap util.h from SDK with ifndef/endif, to avoid problems from multiple -// inclusions. Dunno why Valve didn't do that in util.h themselves.. - -#ifndef SDK_UTIL_H -#define SDK_UTIL_H +#pragma once // We're not including the DBG_EntOfVars and DBG_AssertFunction routines // mentioned in the SDK util.h, so we're going to unset DEBUG here so that @@ -27,65 +23,54 @@ #define QUERY_CLIENT_CVAR_VALUE (*g_engfuncs.pfnQueryClientCvarValue) #define QUERY_CLIENT_CVAR_VALUE2 (*g_engfuncs.pfnQueryClientCvarValue2) -// Add overloaded ENTINDEX() version for const edict_t pointer. -// The pfnIndexOfEdict() function takes a const edict_t pointer -// as parameter anyway, so there is no reason why ENTINDEX() -// shouldn't. -inline int ENTINDEX(const edict_t *pEdict) -{ - return((*g_engfuncs.pfnIndexOfEdict)(pEdict)); -} - // Also, create some nice inlines for engine callback combos. // Get a setinfo value from a player entity. -inline char * DLLINTERNAL ENTITY_KEYVALUE(edict_t *entity, char *key) +inline char *ENTITY_KEYVALUE(edict_t *entity, char *key) { - return(INFOKEY_VALUE(GET_INFOKEYBUFFER(entity), key)); + return INFOKEY_VALUE(GET_INFOKEYBUFFER(entity), key); } // Set a setinfo value for a player entity. -inline void DLLINTERNAL ENTITY_SET_KEYVALUE(edict_t *entity, char *key, char *value) +inline void ENTITY_SET_KEYVALUE(edict_t *entity, char *key, char *value) { SET_CLIENT_KEYVALUE(ENTINDEX(entity), GET_INFOKEYBUFFER(entity), key, value); } // Get a "serverinfo" value. -inline char * DLLINTERNAL SERVERINFO(char *key) +inline char *SERVERINFO(char *key) { - return(ENTITY_KEYVALUE(INDEXENT(0), key)); + return ENTITY_KEYVALUE(INDEXENT(0), key); } // Set a "serverinfo" value. -inline void DLLINTERNAL SET_SERVERINFO(char *key, char *value) +inline void SET_SERVERINFO(char *key, char *value) { SET_SERVER_KEYVALUE(GET_INFOKEYBUFFER(INDEXENT(0)), key, value); } // Get a "localinfo" value. -inline char * DLLINTERNAL LOCALINFO(char *key) +inline char *LOCALINFO(char *key) { - return(ENTITY_KEYVALUE(NULL, key)); + return ENTITY_KEYVALUE(NULL, key); } // Set a "localinfo" value. -inline void DLLINTERNAL SET_LOCALINFO(char *key, char *value) +inline void SET_LOCALINFO(char *key, char *value) { SET_SERVER_KEYVALUE(GET_INFOKEYBUFFER(NULL), key, value); } -inline int DLLINTERNAL fast_FNullEnt(const edict_t* pent) +inline int fast_FNullEnt(const edict_t* pent) { - return(!pent || !(*g_engfuncs.pfnEntOffsetOfPEntity)(pent)); + return !pent || !(*g_engfuncs.pfnEntOffsetOfPEntity)(pent); } // Our slightly modified version, using an edict_t pointer instead of a // CBaseEntity pointer. (was in 1.17p1, included in 1.17.1) -void DLLINTERNAL META_UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage); +void META_UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage); -const char * DLLINTERNAL META_UTIL_VarArgs(const char *format, ...); +const char *META_UTIL_VarArgs(const char *format, ...); -short DLLINTERNAL FixedSigned16(float value, float scale); -unsigned short DLLINTERNAL FixedUnsigned16(float value, float scale); - -#endif /* SDK_UTIL_H */ +short FixedSigned16(float value, float scale); +unsigned short FixedUnsigned16(float value, float scale); diff --git a/src/support_meta.cpp b/metamod/src/support_meta.cpp similarity index 59% rename from src/support_meta.cpp rename to metamod/src/support_meta.cpp index c352028..f39ea2f 100644 --- a/src/support_meta.cpp +++ b/metamod/src/support_meta.cpp @@ -1,11 +1,8 @@ -#include // always -#include // GameDLL -#include "support_meta.h" // me -#include "osdep.h" // sleep, etc +#include "precompiled.h" META_ERRNO meta_errno; -void DLLINTERNAL do_exit(int exitval) +void do_exit(int exitval) { sleep(3); exit(exitval); @@ -18,45 +15,51 @@ void DLLINTERNAL do_exit(int exitval) // Also, formerly named just "valid_file". // // Special-case-recognize "/dev/null" as a valid file. -int DLLINTERNAL valid_gamedir_file(const char *path) +int valid_gamedir_file(const char *path) { char buf[PATH_MAX]; struct stat st; int ret, reg, size; - if(!path) - return(FALSE); + if (!path) + return FALSE; - if(strmatch(path, "/dev/null")) - return(TRUE); + if (!Q_strcmp(path, "/dev/null")) + return TRUE; - if(is_absolute_path(path)) - STRNCPY(buf, path, sizeof(buf)); + if (is_absolute_path(path)) + { + Q_strncpy(buf, path, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + } else safevoid_snprintf(buf, sizeof(buf), "%s/%s", GameDLL.gamedir, path); - ret=stat(buf, &st); - if(ret != 0) { + ret = stat(buf, &st); + if (ret != 0) + { META_DEBUG(5, ("Unable to stat '%s': %s", buf, strerror(errno))); - return(FALSE); + return FALSE; } - reg=S_ISREG(st.st_mode); - if(!reg) { + reg = S_ISREG(st.st_mode); + if (!reg) + { META_DEBUG(5, ("Not a regular file: %s", buf)); - return(FALSE); + return FALSE; } - size=st.st_size; - if(!size) { + size = st.st_size; + if (!size) + { META_DEBUG(5, ("Empty file: %s", buf)); - return(FALSE); + return FALSE; } - if(ret==0 && reg && size) - return(TRUE); + if (ret == 0 && reg && size) + return TRUE; else - return(FALSE); + return FALSE; } // Turns path into a full path: @@ -64,23 +67,29 @@ int DLLINTERNAL valid_gamedir_file(const char *path) // - calls realpath() to collapse ".." and such // - calls normalize_pathname() to fix backslashes, etc // -// Much like realpath, buffer pointed to by fullpath is assumed to be +// Much like realpath, buffer pointed to by fullpath is assumed to be // able to store a string of PATH_MAX length. -char * DLLINTERNAL full_gamedir_path(const char *path, char *fullpath) { +char *full_gamedir_path(const char *path, char *fullpath) { char buf[PATH_MAX]; // Build pathname from filename, plus gamedir if relative path. - if(is_absolute_path(path)) - STRNCPY(buf, path, sizeof(buf)); + if (is_absolute_path(path)) + { + Q_strncpy(buf, path, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + } else safevoid_snprintf(buf, sizeof(buf), "%s/%s", GameDLL.gamedir, path); + // Remove relative path components, if possible. - if(!realpath(buf, fullpath)) { - META_DEBUG(4, ("Unable to get realpath for '%s': %s", buf, - str_os_error())); - STRNCPY(fullpath, path, PATH_MAX); + if (!realpath(buf, fullpath)) + { + META_DEBUG(4, ("Unable to get realpath for '%s': %s", buf, str_os_error())); + + Q_strncpy(fullpath, path, sizeof(fullpath) - 1); + fullpath[sizeof(fullpath) - 1] = '\0'; } // Replace backslashes, etc. normalize_pathname(fullpath); - return(fullpath); + return fullpath; } diff --git a/src/support_meta.h b/metamod/src/support_meta.h similarity index 54% rename from src/support_meta.h rename to metamod/src/support_meta.h index b2ba748..27e9196 100644 --- a/src/support_meta.h +++ b/metamod/src/support_meta.h @@ -8,27 +8,7 @@ #include "osdep.h" // strcasecmp, S_ISREG, #include "enginecallbacks.h" // LOAD_FILE_FOR_ME, etc -void DLLINTERNAL do_exit(int exitval); - -//use pointer to avoid inlining of strcmp -inline int DLLINTERNAL mm_strcmp(const char *s1, const char *s2) { -#if 0 - int (*__strcmp)(const char*, const char*) = &Q_strcmp; - return((*__strcmp)(s1, s2)); -#else - return(Q_strcmp(s1,s2)); -#endif -} - -//use pointer to avoid inlining of strncmp -inline int DLLINTERNAL mm_strncmp(const char *s1, const char *s2, size_t n) { -#if 0 - int (*__strncmp)(const char*, const char*, size_t) = &Q_strncmp; - return((*__strncmp)(s1, s2, n)); -#else - return(Q_strncmp(s1,s2,n)); -#endif -} +void do_exit(int exitval); // Unlike snprintf(), strncpy() doesn't necessarily null-terminate the // target. It appears the former function reasonably considers the given @@ -59,61 +39,9 @@ inline int DLLINTERNAL mm_strncmp(const char *s1, const char *s2, size_t n) { // statements. // Technique 1: use "do..while": -#if 0 -#define STRNCPY(dst, src, size) \ - do { Q_strcpy(dst, "\0"); Q_strncat(dst, src, size-1); } while(0) -#endif -// Technique 2: use parens and commas: -#if 0 -#define STRNCPY(dst, src, size) \ - (Q_strcpy(dst, "\0"), Q_strncat(dst, src, size-1)) -#endif - -// Technique 3: use inline -inline char * DLLINTERNAL STRNCPY(char *dst, const char *src, int size) { - return(Q_strncat(&(*dst = 0), src, size-1)); -} - -// Renamed string functions to be clearer. -inline int DLLINTERNAL strmatch(const char *s1, const char *s2) { - if(likely(s1) && likely(s2)) - return(!mm_strcmp(s1, s2)); - else - return(0); -} -inline int DLLINTERNAL strnmatch(const char *s1, const char *s2, size_t n) { - if(likely(s1) && likely(s2)) - return(!mm_strncmp(s1, s2, n)); - else - return(0); -} -inline int DLLINTERNAL strcasematch(const char *s1, const char *s2) { - if(likely(s1) && likely(s2)) - return(!strcasecmp(s1, s2)); - else - return(0); -} -inline int DLLINTERNAL strncasematch(const char *s1, const char *s2, size_t n) { - if(likely(s1) && likely(s2)) - return(!strncasecmp(s1, s2, n)); - else - return(0); -} - -inline int DLLINTERNAL old_valid_file(char *path) { - char *cp; - int len, ret; - cp = (char *)LOAD_FILE_FOR_ME(path, &len); - if(cp && len) - ret=1; - else - ret=0; - FREE_FILE(cp); - return(ret); -} -int DLLINTERNAL valid_gamedir_file(const char *path); -char * DLLINTERNAL full_gamedir_path(const char *path, char *fullpath); +int valid_gamedir_file(const char *path); +char *full_gamedir_path(const char *path, char *fullpath); // Turn a variable/function name into the corresponding string, optionally // stripping off the leading "len" characters. Useful for things like diff --git a/src/types_meta.h b/metamod/src/types_meta.h similarity index 84% rename from src/types_meta.h rename to metamod/src/types_meta.h index bf02381..99a81aa 100644 --- a/src/types_meta.h +++ b/metamod/src/types_meta.h @@ -1,5 +1,4 @@ -#ifndef TYPES_META_H -#define TYPES_META_H +#pragma once #include "comp_dep.h" @@ -11,7 +10,8 @@ typedef enum mBOOL { // Like C's errno, for our various functions; describes causes of failure // or mFALSE returns. -typedef enum { +enum META_ERRNO +{ ME_NOERROR = 0, ME_FORMAT, // invalid format ME_COMMENT, // ignored comment @@ -36,13 +36,12 @@ typedef enum { ME_IFVERSION, // incompatible interface version ME_UNLOAD_UNLOADER, // tried to unload unloader ME_UNLOAD_SELF, // tried to unload self -} META_ERRNO; -extern META_ERRNO meta_errno DLLHIDDEN; +}; + +extern META_ERRNO meta_errno; #define RETURN_ERRNO(retval, errval) \ - do { meta_errno=errval; return(retval); } while(0) + do { meta_errno=errval; return retval; } while (0) #define RETURN_LOGERR_ERRNO(errargs, retval, errval) \ - do { META_ERROR errargs ; meta_errno=errval; return(retval); } while(0) - -#endif /* TYPES_META_H */ + do { META_ERROR errargs ; meta_errno=errval; return retval; } while (0) diff --git a/metamod/version/appversion.vm b/metamod/version/appversion.vm new file mode 100644 index 0000000..47afd72 --- /dev/null +++ b/metamod/version/appversion.vm @@ -0,0 +1,27 @@ +#ifndef __APPVERSION_H__ +\#define __APPVERSION_H__ + +// +// This file is generated automatically. +// Don't edit it. +// + +// Version defines +\#define VERSION_MAJOR ${verInfo.majorVersion} +\#define VERSION_MINOR ${verInfo.minorVersion} + +\#define APP_COMMIT_AUTHOR "(${verInfo.authorCommit})" +\#define APP_COMMIT_ID "${verInfo.commitID}" +\#define APP_COMMITS_URL "${verInfo.urlCommits}" + +\#define APP_VERSION_D ${verInfo.format('.', '-', true)} +\#define APP_VERSION_C ${verInfo.majorVersion},${verInfo.minorVersion},0,${verInfo.countCommit} + +\#define APP_VERSION_STRD "${verInfo.majorVersion}.${verInfo.minorVersion}.${verInfo.countCommit}" +\#define APP_VERSION_STRD_RC "${verInfo.majorVersion}.${verInfo.minorVersion}.${verInfo.countCommit}" +#set ( $commitYMD = $_DateTimeFormat.forPattern('yyyy-MM-dd').print($verInfo.lastCommitDate) ) + +\#define APP_VERSION_YMD_STR "${commitYMD}" +\#define APP_VERSION APP_VERSION_STRD + +#endif //__APPVERSION_H__ diff --git a/metamod/version/version.cpp b/metamod/version/version.cpp new file mode 100644 index 0000000..5089a5f --- /dev/null +++ b/metamod/version/version.cpp @@ -0,0 +1,10 @@ +/* +* Version declaration dependency file +* +*/ + +// +// This file needed just to add the dependency and appversion.h +// +#include "precompiled.h" + diff --git a/msvc/metamod.sln b/msvc/metamod.sln index 948824c..543cc94 100644 --- a/msvc/metamod.sln +++ b/msvc/metamod.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30501.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "metamod", "metamod.vcxproj", "{02832A39-E902-46B7-8D47-911C37CF41B0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "metamod", "..\metamod\msvc\metamod.vcxproj", "{02832A39-E902-46B7-8D47-911C37CF41B0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/msvc/metamod.vcxproj b/msvc/metamod.vcxproj deleted file mode 100644 index 6919498..0000000 --- a/msvc/metamod.vcxproj +++ /dev/null @@ -1,166 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {02832A39-E902-46B7-8D47-911C37CF41B0} - metamod - Win32Proj - - - - DynamicLibrary - v120_xp - MultiByte - true - - - DynamicLibrary - v120 - NotSet - - - - - - - - - - - - - <_ProjectFileVersion>12.0.30501.0 - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - - - - Disabled - ..\src;..\sdk\common;..\sdk\dlls;..\sdk\engine;..\sdk\pm_shared;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;METAMOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;__METAMOD_BUILD__;__BUILD_FAST_METAMOD__;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - Level3 - EditAndContinue - - - metamod.def - true - Windows - MachineX86 - psapi.lib;$(ProjectDir)../lib/libirc.lib;$(ProjectDir)../lib/libacof32.lib;%(AdditionalDependencies) - - - - - ..\src;..\sdk\common;..\sdk\dlls;..\sdk\engine;..\sdk\pm_shared;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;METAMOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;__METAMOD_BUILD__;__BUILD_FAST_METAMOD__;%(PreprocessorDefinitions) - MultiThreaded - - Level3 - ProgramDatabase - Default - StreamingSIMDExtensions2 - - - true - Windows - true - true - MachineX86 - psapi.lib;$(ProjectDir)../lib/libirc.lib;$(ProjectDir)../lib/libacof32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/msvc/res_meta.rc b/msvc/res_meta.rc deleted file mode 100644 index 53ccef9..0000000 --- a/msvc/res_meta.rc +++ /dev/null @@ -1,76 +0,0 @@ -// vi: set ts=4 sw=4 ft=c : -// vim: set tw=75 : - -/* - * Copyright (c) 2001-2003 Will Day - * - * This file is part of Metamod. - * - * Metamod is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Metamod is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Metamod; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, the author gives permission to - * link the code of this program with the Half-Life Game Engine ("HL - * Engine") and Modified Game Libraries ("MODs") developed by Valve, - * L.L.C ("Valve"). You must obey the GNU General Public License in all - * respects for all of the code used other than the HL Engine and MODs - * from Valve. If you modify this file, you may extend this exception - * to your version of the file, but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. - * - */ - -// see: -// http://msdn.microsoft.com/library/psdk/winui/rc_7x2d.htm - -#include -#include "..\src\info_name.h" - -VS_VERSION_INFO VERSIONINFO - FILEVERSION RC_VERS_DWORD - PRODUCTVERSION RC_VERS_DWORD - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", RC_COMMENTS "\0" - VALUE "CompanyName", VAUTHOR "\0" - VALUE "FileDescription", RC_DESC "\0" - VALUE "FileVersion", VVERSION "\0" - VALUE "InternalName", RC_INTERNAL "\0" - VALUE "LegalCopyright", RC_COPYRIGHT "\0" - VALUE "License", RC_LICENSE "\0" - VALUE "OriginalFilename", RC_FILENAME "\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", VNAME "\0" - VALUE "ProductVersion", VVERSION "\0" - VALUE "SpecialBuild", OPT_TYPE "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/publish.gradle b/publish.gradle new file mode 100644 index 0000000..974d434 --- /dev/null +++ b/publish.gradle @@ -0,0 +1,38 @@ +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.apache.commons.io.FilenameUtils + +void _copyFileToDir(String from, String to) { + def dst = new File(project.file(to), FilenameUtils.getName(from)) + GradleCppUtils.copyFile(project.file(from), dst, false) +} + +void _copyFile(String from, String to) { + GradleCppUtils.copyFile(project.file(from), project.file(to), false) +} + +task publishPrepareFiles << { + def pubRootDir = project.file('publish/publishRoot') + if (pubRootDir.exists()) { + if (!pubRootDir.deleteDir()) { + throw new RuntimeException("Failed to delete ${pubRootDir}") + } + } + + pubRootDir.mkdirs() + project.file('publish/publishRoot/metamod/addons/metamod').mkdirs() + + _copyFileToDir('publish/metamod_mm.dll', 'publish/publishRoot/metamod/addons/metamod/') + //_copyFileToDir('publish/metamod_mm.pdb', 'publish/publishRoot/metamod/addons/metamod/') + _copyFile('publish/libmetamod_mm_i386.so', 'publish/publishRoot/metamod/addons/metamod/metamod_mm_i386.so') +} + +task publishPackage(type: Zip, dependsOn: 'publishPrepareFiles') { + baseName = "metamod_${project.version}" + destinationDir file('publish') + from 'publish/publishRoot/metamod' +} + +task doPackage { + dependsOn 'publishPackage' + +} diff --git a/sdk/common/com_model.h b/sdk/common/com_model.h deleted file mode 100644 index 6069e30..0000000 --- a/sdk/common/com_model.h +++ /dev/null @@ -1,362 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// com_model.h -#if !defined( COM_MODEL_H ) -#define COM_MODEL_H -#if defined( _WIN32 ) -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#define STUDIO_RENDER 1 -#define STUDIO_EVENTS 2 - -#define MAX_CLIENTS 32 -#define MAX_EDICTS 900 - -#define MAX_MODEL_NAME 64 -#define MAX_MAP_HULLS 4 -#define MIPLEVELS 4 -#define NUM_AMBIENTS 4 // automatic ambient sounds -#define MAXLIGHTMAPS 4 -#define PLANE_ANYZ 5 - -#define ALIAS_Z_CLIP_PLANE 5 - -// flags in finalvert_t.flags -#define ALIAS_LEFT_CLIP 0x0001 -#define ALIAS_TOP_CLIP 0x0002 -#define ALIAS_RIGHT_CLIP 0x0004 -#define ALIAS_BOTTOM_CLIP 0x0008 -#define ALIAS_Z_CLIP 0x0010 -#define ALIAS_ONSEAM 0x0020 -#define ALIAS_XY_CLIP_MASK 0x000F - -#define ZISCALE ((float)0x8000) - -#define CACHE_SIZE 32 // used to align key data structures - -typedef enum -{ - mod_brush, - mod_sprite, - mod_alias, - mod_studio -} modtype_t; - -// must match definition in modelgen.h -#ifndef SYNCTYPE_T -#define SYNCTYPE_T - -typedef enum -{ - ST_SYNC=0, - ST_RAND -} synctype_t; - -#endif - -typedef struct -{ - float mins[3], maxs[3]; - float origin[3]; - int headnode[MAX_MAP_HULLS]; - int visleafs; // not including the solid leaf 0 - int firstface, numfaces; -} dmodel_t; - -// plane_t structure -#ifndef _MPLANE_DEFINED_ -#define _MPLANE_DEFINED_ -typedef struct mplane_s -{ - vec3_t normal; // surface normal - float dist; // closest appoach to origin - byte type; // for texture axis selection and fast side tests - byte signbits; // signx + signy<<1 + signz<<1 - byte pad[2]; -} mplane_t; -#endif - -typedef struct -{ - vec3_t position; -} mvertex_t; - -typedef struct -{ - unsigned short v[2]; - unsigned int cachededgeoffset; -} medge_t; - -typedef struct texture_s -{ - char name[16]; - unsigned width, height; - int anim_total; // total tenths in sequence ( 0 = no) - int anim_min, anim_max; // time for this frame min <=time< max - struct texture_s *anim_next; // in the animation sequence - struct texture_s *alternate_anims; // bmodels in frame 1 use these - unsigned offsets[MIPLEVELS]; // four mip maps stored - unsigned paloffset; -} texture_t; - -typedef struct -{ - float vecs[2][4]; // [s/t] unit vectors in world space. - // [i][3] is the s/t offset relative to the origin. - // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] - float mipadjust; // ?? mipmap limits for very small surfaces - texture_t *texture; - int flags; // sky or slime, no lightmap or 256 subdivision -} mtexinfo_t; - -typedef struct mnode_s -{ -// common with leaf - int contents; // 0, to differentiate from leafs - int visframe; // node needs to be traversed if current - - short minmaxs[6]; // for bounding box culling - - struct mnode_s *parent; - -// node specific - mplane_t *plane; - struct mnode_s *children[2]; - - unsigned short firstsurface; - unsigned short numsurfaces; -} mnode_t; - -typedef struct msurface_s msurface_t; -typedef struct decal_s decal_t; - -// JAY: Compress this as much as possible -struct decal_s -{ - decal_t *pnext; // linked list for each surface - msurface_t *psurface; // Surface id for persistence / unlinking - short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) - short dy; - short texture; // Decal texture - byte scale; // Pixel scale - byte flags; // Decal flags - - short entityIndex; // Entity this is attached to -}; - -typedef struct mleaf_s -{ -// common with node - int contents; // wil be a negative contents number - int visframe; // node needs to be traversed if current - - short minmaxs[6]; // for bounding box culling - - struct mnode_s *parent; - -// leaf specific - byte *compressed_vis; - struct efrag_s *efrags; - - msurface_t **firstmarksurface; - int nummarksurfaces; - int key; // BSP sequence number for leaf's contents - byte ambient_sound_level[NUM_AMBIENTS]; -} mleaf_t; - -struct msurface_s -{ - int visframe; // should be drawn when node is crossed - - int dlightframe; // last frame the surface was checked by an animated light - int dlightbits; // dynamically generated. Indicates if the surface illumination - // is modified by an animated light. - - mplane_t *plane; // pointer to shared plane - int flags; // see SURF_ #defines - - int firstedge; // look up in model->surfedges[], negative numbers - int numedges; // are backwards edges - -// surface generation data - struct surfcache_s *cachespots[MIPLEVELS]; - - short texturemins[2]; // smallest s/t position on the surface. - short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces - - mtexinfo_t *texinfo; - -// lighting info - byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights - // no one surface can be effected by more than 4 - // animated lights. - color24 *samples; - - decal_t *pdecals; -}; - -#ifndef _DCLIPNODE_DEFINED_ -#define _DCLIPNODE_DEFINED_ -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; -#endif - -#ifndef _HULL_DEFINED_ -#define _HULL_DEFINED_ -typedef struct hull_s -{ - dclipnode_t *clipnodes; - mplane_t *planes; - int firstclipnode; - int lastclipnode; - vec3_t clip_mins; - vec3_t clip_maxs; -} hull_t; -#endif - -#if !defined( CACHE_USER ) && !defined( QUAKEDEF_H ) -#define CACHE_USER -typedef struct cache_user_s -{ - void *data; -} cache_user_t; -#endif - -typedef struct model_s -{ - char name[ MAX_MODEL_NAME ]; - qboolean needload; // bmodels and sprites don't cache normally - - modtype_t type; - int numframes; - synctype_t synctype; - - int flags; - -// -// volume occupied by the model -// - vec3_t mins, maxs; - float radius; - -// -// brush model -// - int firstmodelsurface, nummodelsurfaces; - - int numsubmodels; - dmodel_t *submodels; - - int numplanes; - mplane_t *planes; - - int numleafs; // number of visible leafs, not counting 0 - struct mleaf_s *leafs; - - int numvertexes; - mvertex_t *vertexes; - - int numedges; - medge_t *edges; - - int numnodes; - mnode_t *nodes; - - int numtexinfo; - mtexinfo_t *texinfo; - - int numsurfaces; - msurface_t *surfaces; - - int numsurfedges; - int *surfedges; - - int numclipnodes; - dclipnode_t *clipnodes; - - int nummarksurfaces; - msurface_t **marksurfaces; - - hull_t hulls[MAX_MAP_HULLS]; - - int numtextures; - texture_t **textures; - - byte *visdata; - - color24 *lightdata; - - char *entities; - -// -// additional model data -// - cache_user_t cache; // only access through Mod_Extradata - -} model_t; - -typedef vec_t vec4_t[4]; - -typedef struct alight_s -{ - int ambientlight; // clip at 128 - int shadelight; // clip at 192 - ambientlight - vec3_t color; - float *plightvec; -} alight_t; - -typedef struct auxvert_s -{ - float fv[3]; // viewspace x, y -} auxvert_t; - -#include "custom.h" - -#define MAX_INFO_STRING 256 -#define MAX_SCOREBOARDNAME 32 -typedef struct player_info_s -{ - // User id on server - int userid; - - // User info string - char userinfo[ MAX_INFO_STRING ]; - - // Name - char name[ MAX_SCOREBOARDNAME ]; - - // Spectator or not, unused - int spectator; - - int ping; - int packet_loss; - - // skin information - char model[MAX_QPATH]; - int topcolor; - int bottomcolor; - - // last frame rendered - int renderframe; - - // Gait frame estimation - int gaitsequence; - float gaitframe; - float gaityaw; - vec3_t prevgaitorigin; - - customization_t customdata; -} player_info_t; - -#endif // #define COM_MODEL_H diff --git a/sdk/common/crc.h b/sdk/common/crc.h deleted file mode 100644 index 9eb306c..0000000 --- a/sdk/common/crc.h +++ /dev/null @@ -1,67 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* crc.h */ -#ifndef CRC_H -#define CRC_H -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#include "archtypes.h" // DAL - -// MD5 Hash -typedef struct -{ - unsigned int buf[4]; - unsigned int bits[2]; - unsigned char in[64]; -} MD5Context_t; - - -#ifdef _WIN32 -typedef uint32 CRC32_t; -#else -typedef uint32 CRC32_t; -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif -void CRC32_Init(CRC32_t *pulCRC); -CRC32_t CRC32_Final(CRC32_t pulCRC); -void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *p, int len); -void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); -int CRC_File(CRC32_t *crcvalue, char *pszFileName); -#ifdef __cplusplus -} -#endif -unsigned char COM_BlockSequenceCRCByte (unsigned char *base, int length, int sequence); - -void MD5Init(MD5Context_t *context); -void MD5Update(MD5Context_t *context, unsigned char const *buf, - unsigned int len); -void MD5Final(unsigned char digest[16], MD5Context_t *context); -void Transform(unsigned int buf[4], unsigned int const in[16]); - -int MD5_Hash_File(unsigned char digest[16], char *pszFileName, int bUsefopen, int bSeed, unsigned int seed[4]); -char *MD5_Print(unsigned char hash[16]); -int MD5_Hash_CachedFile(unsigned char digest[16], unsigned char *pCache, int nFileSize, int bSeed, unsigned int seed[4]); - -int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); - -#endif diff --git a/sdk/common/cvardef.h b/sdk/common/cvardef.h deleted file mode 100644 index eee51d9..0000000 --- a/sdk/common/cvardef.h +++ /dev/null @@ -1,37 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CVARDEF_H -#define CVARDEF_H - -#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc -#define FCVAR_USERINFO (1<<1) // changes the client's info string -#define FCVAR_SERVER (1<<2) // notifies players when changed -#define FCVAR_EXTDLL (1<<3) // defined by external DLL -#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll -#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value -#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. -#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). -#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log -#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar - -typedef struct cvar_s -{ - const char *name; - const char *string; - int flags; - float value; - struct cvar_s *next; -} cvar_t; -#endif diff --git a/sdk/common/interface.cpp b/sdk/common/interface.cpp deleted file mode 100644 index 69c5345..0000000 --- a/sdk/common/interface.cpp +++ /dev/null @@ -1,150 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#include -#include -#include "interface.h" - -#ifndef _WIN32 // LINUX -#include -#include // getcwd -#include // sprintf -#endif - - -// ------------------------------------------------------------------------------------ // -// InterfaceReg. -// ------------------------------------------------------------------------------------ // -InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; - - -InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : - m_pName(pName) -{ - m_CreateFn = fn; - m_pNext = s_pInterfaceRegs; - s_pInterfaceRegs = this; -} - - - -// ------------------------------------------------------------------------------------ // -// CreateInterface. -// ------------------------------------------------------------------------------------ // -EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) -{ - InterfaceReg *pCur; - - for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) - { - if(strcmp(pCur->m_pName, pName) == 0) - { - if ( pReturnCode ) - { - *pReturnCode = IFACE_OK; - } - return pCur->m_CreateFn(); - } - } - - if ( pReturnCode ) - { - *pReturnCode = IFACE_FAILED; - } - return NULL; -} - - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#endif - - -#ifdef _WIN32 -HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) -{ - return (HINTERFACEMODULE)LoadLibrary(pModuleName); -} - -#else // LINUX -HINTERFACEMODULE Sys_LoadModule(const char *pModuleName) -{ - // Linux dlopen() doesn't look in the current directory for libraries. - // We tell it to, so people don't have to 'install' libraries as root. - - char szCwd[1024]; - char szAbsoluteLibFilename[1024]; - - getcwd( szCwd, sizeof( szCwd ) ); - if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) - szCwd[ strlen( szCwd ) - 1 ] = 0; - - sprintf( szAbsoluteLibFilename, "%s/%s", szCwd, pModuleName ); - - return (HINTERFACEMODULE)dlopen( szAbsoluteLibFilename, RTLD_NOW ); -} - -#endif - - -#ifdef _WIN32 -void Sys_FreeModule(HINTERFACEMODULE hModule) -{ - if(!hModule) - return; - - FreeLibrary((HMODULE)hModule); -} - -#else // LINUX -void Sys_FreeModule(HINTERFACEMODULE hModule) -{ - if(!hModule) - return; - - dlclose( (void *)hModule ); -} - -#endif - - -//----------------------------------------------------------------------------- -// Purpose: returns the instance of this module -// Output : interface_instance_t -//----------------------------------------------------------------------------- -CreateInterfaceFn Sys_GetFactoryThis( void ) -{ - return CreateInterface; -} - - -//----------------------------------------------------------------------------- -// Purpose: returns the instance of the named module -// Input : *pModuleName - name of the module -// Output : interface_instance_t - instance of that module -//----------------------------------------------------------------------------- - -#ifdef _WIN32 -CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) -{ - if(!hModule) - return NULL; - - return (CreateInterfaceFn)GetProcAddress((HMODULE)hModule, CREATEINTERFACE_PROCNAME); -} - -#else // LINUX -CreateInterfaceFn Sys_GetFactory( HINTERFACEMODULE hModule ) -{ - if(!hModule) - return NULL; - - return (CreateInterfaceFn)dlsym( (void *)hModule, CREATEINTERFACE_PROCNAME ); -} - -#endif diff --git a/sdk/common/mathlib.h b/sdk/common/mathlib.h deleted file mode 100644 index f5a0c37..0000000 --- a/sdk/common/mathlib.h +++ /dev/null @@ -1,158 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// mathlib.h - -typedef float vec_t; -#ifndef DID_VEC3_T_DEFINE -#define DID_VEC3_T_DEFINE -typedef vec_t vec3_t[3]; -#endif -typedef vec_t vec4_t[4]; // x,y,z,w -typedef vec_t vec5_t[5]; - -typedef short vec_s_t; -typedef vec_s_t vec3s_t[3]; -typedef vec_s_t vec4s_t[4]; // x,y,z,w -typedef vec_s_t vec5s_t[5]; - -typedef int fixed4_t; -typedef int fixed8_t; -typedef int fixed16_t; -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -struct mplane_s; - -extern vec3_t vec3_origin; -extern int nanmask; - -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) - -#ifndef VECTOR_H - #define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -#endif - -#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} -#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} -#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} -#define VectorClear(a) {(a)[0]=0.0;(a)[1]=0.0;(a)[2]=0.0;} - -void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc); - -vec_t _DotProduct (vec3_t v1, vec3_t v2); -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out); -void _VectorCopy (vec3_t in, vec3_t out); - -int VectorCompare (const vec3_t v1, const vec3_t v2); -float Length (const vec3_t v); -void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross); -float VectorNormalize (vec3_t v); // returns vector length -void VectorInverse (vec3_t v); -void VectorScale (const vec3_t in, vec_t scale, vec3_t out); -int Q_log2(int val); - -void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); -void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); - -// Here are some "manual" INLINE routines for doing floating point to integer conversions -extern short new_cw, old_cw; - -typedef union DLONG { - int i[2]; - double d; - float f; - } DLONG; - -extern DLONG dlong; - -#ifdef _WIN32 -void __inline set_fpu_cw(void) -{ -_asm - { wait - fnstcw old_cw - wait - mov ax, word ptr old_cw - or ah, 0xc - mov word ptr new_cw,ax - fldcw new_cw - } -} - -int __inline quick_ftol(float f) -{ - _asm { - // Assumes that we are already in chop mode, and only need a 32-bit int - fld DWORD PTR f - fistp DWORD PTR dlong - } - return dlong.i[0]; -} - -void __inline restore_fpu_cw(void) -{ - _asm fldcw old_cw -} -#else -#define set_fpu_cw() /* */ -#define quick_ftol(f) ftol(f) -#define restore_fpu_cw() /* */ -#endif - -void FloorDivMod (double numer, double denom, int *quotient, - int *rem); -fixed16_t Invert24To16(fixed16_t val); -int GreatestCommonDivisor (int i1, int i2); - -void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -#define AngleIVectors AngleVectorsTranspose - -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ); -void AngleIMatrix (const vec3_t angles, float (*matrix)[4] ); -void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out); - -void NormalizeAngles( vec3_t angles ); -void InterpolateAngles( vec3_t start, vec3_t end, vec3_t output, float frac ); -float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ); - - -void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up); -void VectorAngles( const vec3_t forward, vec3_t angles ); - -int InvertMatrix( const float * m, float *out ); - -int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); -float anglemod(float a); - - - -#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ - (((p)->type < 3)? \ - ( \ - ((p)->dist <= (emins)[(p)->type])? \ - 1 \ - : \ - ( \ - ((p)->dist >= (emaxs)[(p)->type])?\ - 2 \ - : \ - 3 \ - ) \ - ) \ - : \ - BoxOnPlaneSide( (emins), (emaxs), (p))) diff --git a/sdk/common/port.h b/sdk/common/port.h deleted file mode 100644 index c3b2eca..0000000 --- a/sdk/common/port.h +++ /dev/null @@ -1,122 +0,0 @@ -// port.h: portability helper -// -////////////////////////////////////////////////////////////////////// - -#if !defined PORT_H -#define PORT_H - -#include "archtypes.h" // DAL - -#ifdef _WIN32 - -// Insert your headers here -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define WIN32_EXTRA_LEAN - -#include - -#include -#include -#include - -#define snprintf _snprintf -#define vsnprintf _vsnprintf - -#else // _WIN32 - -#include -#include -#include // exit() -#include // strncpy() -#include // tolower() -#include -#include -#include -#include - -typedef unsigned char BYTE; -typedef short int WORD; -typedef unsigned int DWORD; -typedef int32 LONG; -//typedef uint32 ULONG; -#ifndef ARCHTYPES_H -typedef uint32 ULONG; -#endif -typedef void *HANDLE; -#ifndef HMODULE -typedef void *HMODULE; -#endif -typedef char * LPSTR; - -#define __cdecl - - -//const int MAX_PATH = PATH_MAX; -#define MAX_PATH PATH_MAX - -#ifdef LINUX -typedef struct POINT_s -{ - int x; - int y; -} POINT; -typedef void *HINSTANCE; -typedef void *HWND; -typedef void *HDC; -typedef void *HGLRC; - -typedef struct RECT_s -{ - int left; - int right; - int top; - int bottom; -} RECT; -#endif - - -#ifdef __cplusplus - -//#undef FALSE -//#undef TRUE - -#ifdef OSX -//#else -//const bool FALSE = false; -//const bool TRUE = true; -#endif -#endif - -#ifndef NULL - #ifdef __cplusplus - #define NULL 0 - #else - #define NULL ((void *)0) - #endif -#endif - -#ifdef __cplusplus -inline int ioctlsocket( int d, int cmd, uint32 *argp ) { return ioctl( d, cmd, argp ); } -inline int closesocket( int fd ) { return close( fd ); } -inline char * GetCurrentDirectory( size_t size, char * buf ) { return getcwd( buf, size ); } -inline int WSAGetLastError() { return errno; } - -inline void DebugBreak( void ) { exit( 1 ); } -#endif - -extern char g_szEXEName[ 4096 ]; - -#define _snprintf snprintf - -#if defined(OSX) -#define SO_ARCH_SUFFIX ".dylib" -#else -#if defined ( __x86_64__ ) -#define SO_ARCH_SUFFIX "_amd64.so" -#else -#define SO_ARCH_SUFFIX ".so" -#endif -#endif -#endif - -#endif // PORT_H diff --git a/sdk/dlls/AI_BaseNPC_Schedule.cpp b/sdk/dlls/AI_BaseNPC_Schedule.cpp deleted file mode 100644 index 1f83d07..0000000 --- a/sdk/dlls/AI_BaseNPC_Schedule.cpp +++ /dev/null @@ -1,1514 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// schedule.cpp - functions and data pertaining to the -// monsters' AI scheduling system. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "scripted.h" -#include "nodes.h" -#include "defaultai.h" -#include "soundent.h" - -extern CGraph WorldGraph; - -//========================================================= -// FHaveSchedule - Returns TRUE if monster's m_pSchedule -// is anything other than NULL. -//========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) -{ - if ( m_pSchedule == NULL ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// ClearSchedule - blanks out the caller's schedule pointer -// and index. -//========================================================= -void CBaseMonster :: ClearSchedule( void ) -{ - m_iTaskStatus = TASKSTATUS_NEW; - m_pSchedule = NULL; - m_iScheduleIndex = 0; -} - -//========================================================= -// FScheduleDone - Returns TRUE if the caller is on the -// last task in the schedule -//========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - if ( m_iScheduleIndex == m_pSchedule->cTasks ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// ChangeSchedule - replaces the monster's schedule pointer -// with the passed pointer, and sets the ScheduleIndex back -// to 0 -//========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) -{ - ASSERT( pNewSchedule != NULL ); - - m_pSchedule = pNewSchedule; - m_iScheduleIndex = 0; - m_iTaskStatus = TASKSTATUS_NEW; - m_afConditions = 0;// clear all of the conditions - m_failSchedule = SCHED_NONE; - - if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) - { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); - } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) - { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); - } - -#if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) - { - ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); - } -#endif - -// this is very useful code if you can isolate a test case in a level with a single monster. It will notify -// you of every schedule selection the monster makes. -#if 0 - if ( FClassnameIs( pev, "monster_human_grunt" ) ) - { - Task_t *pTask = GetTask(); - - if ( pTask ) - { - const char *pName = NULL; - - if ( m_pSchedule ) - { - pName = m_pSchedule->pName; - } - else - { - pName = "No Schedule"; - } - - if ( !pName ) - { - pName = "Unknown"; - } - - ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); - } - } -#endif// 0 - -} - -//========================================================= -// NextScheduledTask - increments the ScheduleIndex -//========================================================= -void CBaseMonster :: NextScheduledTask ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - m_iTaskStatus = TASKSTATUS_NEW; - m_iScheduleIndex++; - - if ( FScheduleDone() ) - { - // just completed last task in schedule, so make it invalid by clearing it. - SetConditions( bits_COND_SCHEDULE_DONE ); - //ClearSchedule(); - } -} - -//========================================================= -// IScheduleFlags - returns an integer with all Conditions -// bits that are currently set and also set in the current -// schedule's Interrupt mask. -//========================================================= -int CBaseMonster :: IScheduleFlags ( void ) -{ - if( !m_pSchedule ) - { - return 0; - } - - // strip off all bits excepts the ones capable of breaking this schedule. - return m_afConditions & m_pSchedule->iInterruptMask; -} - -//========================================================= -// FScheduleValid - returns TRUE as long as the current -// schedule is still the proper schedule to be executing, -// taking into account all conditions -//========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) -{ - if ( m_pSchedule == NULL ) - { - // schedule is empty, and therefore not valid. - return FALSE; - } - - if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) - { -#ifdef DEBUG - if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) - { - // fail! Send a visual indicator. - ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); - - Vector tmp = pev->origin; - tmp.z = pev->absmax.z + 16; - UTIL_Sparks( tmp ); - } -#endif // DEBUG - - // some condition has interrupted the schedule, or the schedule is done - return FALSE; - } - - return TRUE; -} - -//========================================================= -// MaintainSchedule - does all the per-think schedule maintenance. -// ensures that the monster leaves this function with a valid -// schedule! -//========================================================= -void CBaseMonster :: MaintainSchedule ( void ) -{ - Schedule_t *pNewSchedule; - int i; - - // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible - for ( i = 0; i < 10; i++ ) - { - if ( m_pSchedule != NULL && TaskIsComplete() ) - { - NextScheduledTask(); - } - - // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) - { - // if we come into this block of code, the schedule is going to have to be changed. - // if the previous schedule was interrupted by a condition, GetIdealState will be - // called. Else, a schedule finished normally. - - // Notify the monster that his schedule is changing - ScheduleChange(); - - // Call GetIdealState if we're not dead and one or more of the following... - // - in COMBAT state with no enemy (it died?) - // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, - // - schedule is done but schedule indicates it wants GetIdealState called - // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) - // DEAD & SCRIPT are not suggestions, they are commands! - if ( m_IdealMonsterState != MONSTERSTATE_DEAD && - (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) - { - if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || - (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || - ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == NULL)) ) - { - GetIdealState(); - } - } - if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) - { - if ( m_failSchedule != SCHED_NONE ) - pNewSchedule = GetScheduleOfType( m_failSchedule ); - else - pNewSchedule = GetScheduleOfType( SCHED_FAIL ); - // schedule was invalid because the current task failed to start or complete - ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); - ChangeSchedule( pNewSchedule ); - } - else - { - SetState( m_IdealMonsterState ); - if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) - pNewSchedule = CBaseMonster::GetSchedule(); - else - pNewSchedule = GetSchedule(); - ChangeSchedule( pNewSchedule ); - } - } - - if ( m_iTaskStatus == TASKSTATUS_NEW ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - TaskBegin(); - StartTask( pTask ); - } - - // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) - break; - } - - if ( TaskIsRunning() ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - RunTask( pTask ); - } - - // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation - // RunTask() will always change animations at the end of a script! - // Don't do this twice - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - case TASK_TURN_LEFT: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - { - CBaseEntity *pTarget; - - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) - pTarget = m_hTargetEnt; - else - pTarget = m_hEnemy; - if ( pTarget ) - { - pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - if ( m_fSequenceFinished ) - TaskComplete(); - } - break; - - case TASK_PLAY_SEQUENCE: - case TASK_PLAY_ACTIVE_IDLE: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - - - case TASK_FACE_ENEMY: - { - MakeIdealYaw( m_vecEnemyLKP ); - - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_FACE_HINTNODE: - case TASK_FACE_LASTPOSITION: - case TASK_FACE_TARGET: - case TASK_FACE_IDEAL: - case TASK_FACE_ROUTE: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_PVS: - { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_RANDOM: - { - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - float distance; - - if ( m_hTargetEnt == NULL ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) - m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) - m_movementActivity = ACT_RUN; - } - - break; - } - case TASK_WAIT_FOR_MOVEMENT: - { - if (MovementIsComplete()) - { - TaskComplete(); - RouteClear(); // Stop moving - } - break; - } - case TASK_DIE: - { - if ( m_fSequenceFinished && pev->frame >= 255 ) - { - pev->deadflag = DEAD_DEAD; - - SetThink ( NULL ); - StopAnimation(); - - if ( !BBoxFlat() ) - { - // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will - // block the player on a slope or stairs, the corpse is made nonsolid. -// pev->solid = SOLID_NOT; - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - } - else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem - UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); - - if ( ShouldFadeOnDeath() ) - { - // this monster was created by a monstermaker... fade the corpse out. - SUB_StartFadeOut(); - } - else - { - // body is gonna be around for a while, so have it stink for a bit. - CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); - } - } - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RELOAD_NOTURN: - { - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_RANGE_ATTACK1: - case TASK_MELEE_ATTACK1: - case TASK_MELEE_ATTACK2: - case TASK_RANGE_ATTACK2: - case TASK_SPECIAL_ATTACK1: - case TASK_SPECIAL_ATTACK2: - case TASK_RELOAD: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_SMALL_FLINCH: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - } - break; - case TASK_WAIT_FOR_SCRIPT: - { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); - if ( m_fSequenceFinished ) - ClearSchedule(); - pev->framerate = 1.0; - //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - } - break; - } - case TASK_PLAY_SCRIPT: - { - if (m_fSequenceFinished) - { - m_pCine->SequenceDone( this ); - } - break; - } - } -} - -//========================================================= -// SetTurnActivity - measures the difference between the way -// the monster is facing and determines whether or not to -// select one of the 180 turn animations. -//========================================================= -void CBaseMonster :: SetTurnActivity ( void ) -{ - float flYD; - flYD = FlYawDiff(); - - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn - m_IdealActivity = ACT_TURN_RIGHT; - } - else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn - m_IdealActivity = ACT_TURN_LEFT; - } -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_TURN_LEFT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_REMEMBER: - { - Remember ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FORGET: - { - Forget ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FIND_HINTNODE: - { - m_iHintNode = FindHintNode(); - - if ( m_iHintNode != NO_NODE ) - { - TaskComplete(); - } - else - { - TaskFail(); - } - break; - } - case TASK_STORE_LASTPOSITION: - { - m_vecLastPosition = pev->origin; - TaskComplete(); - break; - } - case TASK_CLEAR_LASTPOSITION: - { - m_vecLastPosition = g_vecZero; - TaskComplete(); - break; - } - case TASK_CLEAR_HINTNODE: - { - m_iHintNode = NO_NODE; - TaskComplete(); - break; - } - case TASK_STOP_MOVING: - { - if ( m_IdealActivity == m_movementActivity ) - { - m_IdealActivity = GetStoppedActivity(); - } - - RouteClear(); - TaskComplete(); - break; - } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - case TASK_PLAY_SEQUENCE: - { - m_IdealActivity = ( Activity )( int )pTask->flData; - break; - } - case TASK_PLAY_ACTIVE_IDLE: - { - // monsters verify that they have a sequence for the node's activity BEFORE - // moving towards the node, so it's ok to just set the activity without checking here. - m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; - break; - } - case TASK_SET_SCHEDULE: - { - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } - else - { - TaskFail(); - } - - break; - } - case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ENEMY: - { - entvars_t *pevCover; - - if ( m_hEnemy == NULL ) - { - // Find cover from self if no enemy available - pevCover = pev; -// TaskFail(); -// return; - } - else - pevCover = m_hEnemy->pev; - - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ORIGIN: - { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no cover! - TaskFail(); - } - } - break; - case TASK_FIND_COVER_FROM_BEST_SOUND: - { - CSound *pBestSound; - - pBestSound = PBestSound(); - - ASSERT( pBestSound != NULL ); - /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - */ - - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. or no sound in list - TaskFail(); - } - break; - } - case TASK_FACE_HINTNODE: - { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; - SetTurnActivity(); - break; - } - - case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); - SetTurnActivity(); - break; - - case TASK_FACE_TARGET: - if ( m_hTargetEnt != NULL ) - { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - SetTurnActivity(); - } - else - TaskFail(); - break; - case TASK_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - SetTurnActivity(); - break; - } - case TASK_FACE_IDEAL: - { - SetTurnActivity(); - break; - } - case TASK_FACE_ROUTE: - { - if (FRouteClear()) - { - ALERT(at_aiconsole, "No route to face!\n"); - TaskFail(); - } - else - { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); - SetTurnActivity(); - } - break; - } - case TASK_WAIT_PVS: - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - } - case TASK_WAIT_RANDOM: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) - TaskFail(); - } - break; - } - case TASK_RUN_TO_TARGET: - case TASK_WALK_TO_TARGET: - { - Activity newActivity; - - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_hTargetEnt == NULL || !MoveToTarget( newActivity, 2 ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - } - TaskComplete(); - break; - } - case TASK_CLEAR_MOVE_WAIT: - { - m_flMoveWaitFinished = gpGlobals->time; - TaskComplete(); - break; - } - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1: - { - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - } - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_MELEE_ATTACK2: - { - m_IdealActivity = ACT_MELEE_ATTACK2; - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2: - { - m_IdealActivity = ACT_RANGE_ATTACK2; - break; - } - case TASK_RELOAD_NOTURN: - case TASK_RELOAD: - { - m_IdealActivity = ACT_RELOAD; - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_SPECIAL_ATTACK2: - { - m_IdealActivity = ACT_SPECIAL_ATTACK2; - break; - } - case TASK_SET_ACTIVITY: - { - m_IdealActivity = (Activity)(int)pTask->flData; - TaskComplete(); - break; - } - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_GET_PATH_TO_SPOT: - { - CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); - if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - - case TASK_GET_PATH_TO_TARGET: - { - RouteClear(); - if ( m_hTargetEnt != NULL && MoveToTarget( m_movementActivity, 1 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! - { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_LASTPOSITION: - { - m_vecMoveGoal = m_vecLastPosition; - - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_BESTSOUND: - { - CSound *pSound; - - pSound = PBestSound(); - - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); - TaskFail(); - } - break; - } -case TASK_GET_PATH_TO_BESTSCENT: - { - CSound *pScent; - - pScent = PBestScent(); - - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - - TaskFail(); - } - break; - } - case TASK_RUN_PATH: - { - // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? - if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_RUN; - } - else - { - m_movementActivity = ACT_WALK; - } - TaskComplete(); - break; - } - case TASK_WALK_PATH: - { - if ( pev->movetype == MOVETYPE_FLY ) - { - m_movementActivity = ACT_FLY; - } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_WALK; - } - else - { - m_movementActivity = ACT_RUN; - } - TaskComplete(); - break; - } - case TASK_STRAFE_PATH: - { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; - - // to start strafing, we have to first figure out if the target is on the left side or right side - UTIL_MakeVectors ( pev->angles ); - - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); - vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) - { - // strafe right - m_movementActivity = ACT_STRAFE_RIGHT; - } - else - { - // strafe left - m_movementActivity = ACT_STRAFE_LEFT; - } - TaskComplete(); - break; - } - - - case TASK_WAIT_FOR_MOVEMENT: - { - if (FRouteClear()) - { - TaskComplete(); - } - break; - } - - case TASK_EAT: - { - Eat( pTask->flData ); - TaskComplete(); - break; - } - case TASK_SMALL_FLINCH: - { - m_IdealActivity = GetSmallFlinchActivity(); - break; - } - case TASK_DIE: - { - RouteClear(); - - m_IdealActivity = GetDeathActivity(); - - pev->deadflag = DEAD_DYING; - break; - } - case TASK_SOUND_WAKE: - { - AlertSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DIE: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_IDLE: - { - IdleSound(); - TaskComplete(); - break; - } - case TASK_SOUND_PAIN: - { - PainSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DEATH: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_ANGRY: - { - // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); - TaskComplete(); - break; - } - case TASK_WAIT_FOR_SCRIPT: - { - if (m_pCine->m_iszIdle) - { - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); - if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) - { - pev->framerate = 0; - } - } - else - m_IdealActivity = ACT_IDLE; - - break; - } - case TASK_PLAY_SCRIPT: - { - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->origin = m_hTargetEnt->pev->origin; // Plant on target - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_hTargetEnt != NULL ) - { - pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); - } - - TaskComplete(); - m_IdealActivity = ACT_IDLE; - RouteClear(); - break; - } - - case TASK_SUGGEST_STATE: - { - m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; - TaskComplete(); - break; - } - - case TASK_SET_FAIL_SCHEDULE: - m_failSchedule = (int)pTask->flData; - TaskComplete(); - break; - - case TASK_CLEAR_FAIL_SCHEDULE: - m_failSchedule = SCHED_NONE; - TaskComplete(); - break; - - default: - { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); - break; - } - } -} - -//========================================================= -// GetTask - returns a pointer to the current -// scheduled task. NULL if there's a problem. -//========================================================= -Task_t *CBaseMonster :: GetTask ( void ) -{ - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) - { - // m_iScheduleIndex is not within valid range for the monster's current schedule. - return NULL; - } - else - { - return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBaseMonster :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_PRONE: - { - return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); - break; - } - case MONSTERSTATE_NONE: - { - ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); - break; - } - case MONSTERSTATE_IDLE: - { - if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else if ( FRouteClear() ) - { - // no valid route! - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - else - { - // valid route. Get moving - return GetScheduleOfType( SCHED_IDLE_WALK ); - } - break; - } - case MONSTERSTATE_ALERT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) - { - return GetScheduleOfType ( SCHED_VICTORY_DANCE ); - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); - } - } - - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_STAND ); - } - break; - } - case MONSTERSTATE_COMBAT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // clear the current (dead) enemy and try to find another. - m_hEnemy = NULL; - - if ( GetEnemy() ) - { - ClearConditions( bits_COND_ENEMY_DEAD ); - return GetSchedule(); - } - else - { - SetState( MONSTERSTATE_ALERT ); - return GetSchedule(); - } - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - else if ( !HasConditions(bits_COND_SEE_ENEMY) ) - { - // we can't see the enemy - if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) - { - // enemy is unseen, but not occluded! - // turn to face enemy - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - // chase! - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - } - else - { - // we can see the enemy - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); - } - if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) - { - // if we can see enemy but can't use either attack type, we must need to get closer to enemy - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - else if ( !FacingIdeal() ) - { - //turn - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); - } - } - break; - } - case MONSTERSTATE_DEAD: - { - return GetScheduleOfType( SCHED_DIE ); - break; - } - case MONSTERSTATE_SCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - - return GetScheduleOfType( SCHED_AISCRIPT ); - } - default: - { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); - break; - } - } - - return &slError[ 0 ]; -} diff --git a/sdk/dlls/Makefile b/sdk/dlls/Makefile deleted file mode 100644 index c0ee3de..0000000 --- a/sdk/dlls/Makefile +++ /dev/null @@ -1,187 +0,0 @@ -# -# Half-Life Full SDK 2.3 hl_i386.so Makefile for x86 Linux -# -# October 2002 by Leon Hartwig (hartwig@valvesoftware.com) -# - -DLLNAME=hl - -ARCH=i386 - -#make sure this is the correct compiler for your system -CC=gcc - -DLL_SRCDIR=. -ENGINE_SRCDIR=../engine -COMMON_SRCDIR=../common -WPN_SHARED_SRCDIR=./wpn_shared -PM_SHARED_SRCDIR=../pm_shared -GAME_SHARED_SRCDIR=../game_shared - -DLL_OBJDIR=$(DLL_SRCDIR)/obj -WPN_SHARED_OBJDIR=$(WPN_SHARED_SRCDIR)/obj -PM_SHARED_OBJDIR=$(PM_SHARED_SRCDIR)/obj -GAME_SHARED_OBJDIR=$(GAME_SHARED_SRCDIR)/obj - -BASE_CFLAGS= -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ - -DCLIENT_WEAPONS - -#safe optimization -CFLAGS=$(BASE_CFLAGS) -Wall -Wno-non-virtual-dtor -Wno-invalid-offsetof -Werror -m486 -O1 -C_FLAGS=$(BASE_CFLAGS) -Wall -Werror -m486 -O1 - -#full optimization -#CFLAGS=$(BASE_CFLAGS) -Wall -Wno-non-virtual-dtor -Wno-invalid-offsetof -Werror -O1 -m486 -ffast-math -funroll-loops \ - -fomit-frame-pointer -fexpensive-optimizations \ - -malign-loops=2 -malign-jumps=2 -malign-functions=2 - -#use these when debugging -#CFLAGS=$(BASE_CFLAGS) -g - -INCLUDEDIRS=-I. -I$(ENGINE_SRCDIR) -I$(COMMON_SRCDIR) -I$(PM_SHARED_SRCDIR) -I$(GAME_SHARED_SRCDIR) - -LDFLAGS= - -SHLIBEXT=so -SHLIBCFLAGS=-fPIC -SHLIBLDFLAGS=-shared - -DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< -DO_C=$(CC) $(C_FLAGS) $(SHLIBCFLAGS) $(INCLUDEDIRS) -o $@ -c $< - -############################################################################# -# SETUP AND BUILD -# GAME -############################################################################# - -$(DLL_OBJDIR)/%.o: $(DLL_SRCDIR)/%.cpp - $(DO_CC) - -$(WPN_SHARED_OBJDIR)/%.o: $(WPN_SHARED_SRCDIR)/%.cpp - $(DO_CC) - -$(GAME_SHARED_OBJDIR)/%.o: $(GAME_SHARED_SRCDIR)/%.cpp - $(DO_CC) - -$(PM_SHARED_OBJDIR)/%.o: $(PM_SHARED_SRCDIR)/%.c - $(DO_C) - -OBJ = \ - $(DLL_OBJDIR)/aflock.o \ - $(DLL_OBJDIR)/agrunt.o \ - $(DLL_OBJDIR)/airtank.o \ - $(DLL_OBJDIR)/animating.o \ - $(DLL_OBJDIR)/animation.o \ - $(DLL_OBJDIR)/apache.o \ - $(DLL_OBJDIR)/barnacle.o \ - $(DLL_OBJDIR)/barney.o \ - $(DLL_OBJDIR)/bigmomma.o \ - $(DLL_OBJDIR)/bloater.o \ - $(DLL_OBJDIR)/bmodels.o \ - $(DLL_OBJDIR)/bullsquid.o \ - $(DLL_OBJDIR)/buttons.o \ - $(DLL_OBJDIR)/cbase.o \ - $(DLL_OBJDIR)/client.o \ - $(DLL_OBJDIR)/combat.o \ - $(DLL_OBJDIR)/controller.o \ - $(DLL_OBJDIR)/crossbow.o \ - $(DLL_OBJDIR)/crowbar.o \ - $(DLL_OBJDIR)/defaultai.o \ - $(DLL_OBJDIR)/doors.o \ - $(DLL_OBJDIR)/effects.o \ - $(DLL_OBJDIR)/egon.o \ - $(DLL_OBJDIR)/explode.o \ - $(DLL_OBJDIR)/flyingmonster.o \ - $(DLL_OBJDIR)/func_break.o \ - $(DLL_OBJDIR)/func_tank.o \ - $(DLL_OBJDIR)/game.o \ - $(DLL_OBJDIR)/gamerules.o \ - $(DLL_OBJDIR)/gargantua.o \ - $(DLL_OBJDIR)/gauss.o \ - $(DLL_OBJDIR)/genericmonster.o \ - $(DLL_OBJDIR)/ggrenade.o \ - $(DLL_OBJDIR)/globals.o \ - $(DLL_OBJDIR)/gman.o \ - $(DLL_OBJDIR)/h_ai.o \ - $(DLL_OBJDIR)/h_battery.o \ - $(DLL_OBJDIR)/h_cine.o \ - $(DLL_OBJDIR)/h_cycler.o \ - $(DLL_OBJDIR)/h_export.o \ - $(DLL_OBJDIR)/handgrenade.o \ - $(DLL_OBJDIR)/hassassin.o \ - $(DLL_OBJDIR)/headcrab.o \ - $(DLL_OBJDIR)/healthkit.o \ - $(DLL_OBJDIR)/hgrunt.o \ - $(DLL_OBJDIR)/hornet.o \ - $(DLL_OBJDIR)/hornetgun.o \ - $(DLL_OBJDIR)/houndeye.o \ - $(DLL_OBJDIR)/ichthyosaur.o \ - $(DLL_OBJDIR)/islave.o \ - $(DLL_OBJDIR)/items.o \ - $(DLL_OBJDIR)/leech.o \ - $(DLL_OBJDIR)/lights.o \ - $(DLL_OBJDIR)/maprules.o \ - $(DLL_OBJDIR)/monstermaker.o \ - $(DLL_OBJDIR)/monsters.o \ - $(DLL_OBJDIR)/monsterstate.o \ - $(DLL_OBJDIR)/mortar.o \ - $(DLL_OBJDIR)/mp5.o \ - $(DLL_OBJDIR)/multiplay_gamerules.o \ - $(DLL_OBJDIR)/nihilanth.o \ - $(DLL_OBJDIR)/nodes.o \ - $(DLL_OBJDIR)/osprey.o \ - $(DLL_OBJDIR)/pathcorner.o \ - $(DLL_OBJDIR)/plane.o \ - $(DLL_OBJDIR)/plats.o \ - $(DLL_OBJDIR)/player.o \ - $(DLL_OBJDIR)/python.o \ - $(DLL_OBJDIR)/rat.o \ - $(DLL_OBJDIR)/roach.o \ - $(DLL_OBJDIR)/rpg.o \ - $(DLL_OBJDIR)/satchel.o \ - $(DLL_OBJDIR)/schedule.o \ - $(DLL_OBJDIR)/scientist.o \ - $(DLL_OBJDIR)/scripted.o \ - $(DLL_OBJDIR)/shotgun.o \ - $(DLL_OBJDIR)/singleplay_gamerules.o \ - $(DLL_OBJDIR)/skill.o \ - $(DLL_OBJDIR)/sound.o \ - $(DLL_OBJDIR)/soundent.o \ - $(DLL_OBJDIR)/spectator.o \ - $(DLL_OBJDIR)/squadmonster.o \ - $(DLL_OBJDIR)/squeakgrenade.o \ - $(DLL_OBJDIR)/subs.o \ - $(DLL_OBJDIR)/talkmonster.o \ - $(DLL_OBJDIR)/teamplay_gamerules.o \ - $(DLL_OBJDIR)/tempmonster.o \ - $(DLL_OBJDIR)/tentacle.o \ - $(DLL_OBJDIR)/triggers.o \ - $(DLL_OBJDIR)/tripmine.o \ - $(DLL_OBJDIR)/turret.o \ - $(DLL_OBJDIR)/util.o \ - $(DLL_OBJDIR)/weapons.o \ - $(DLL_OBJDIR)/world.o \ - $(DLL_OBJDIR)/xen.o \ - $(DLL_OBJDIR)/zombie.o \ - $(WPN_SHARED_OBJDIR)/hl_wpn_glock.o \ - $(GAME_SHARED_OBJDIR)/voice_gamemgr.o \ - $(PM_SHARED_OBJDIR)/pm_debug.o \ - $(PM_SHARED_OBJDIR)/pm_math.o \ - $(PM_SHARED_OBJDIR)/pm_shared.o - -$(DLLNAME)_$(ARCH).$(SHLIBEXT) : neat $(OBJ) - $(CC) $(CFLAGS) $(SHLIBLDFLAGS) $(LDFLAGS) -o $@ $(OBJ) - -neat: - -mkdir -p $(DLL_OBJDIR) - -mkdir -p $(WPN_SHARED_OBJDIR) - -mkdir -p $(GAME_SHARED_OBJDIR) - -mkdir -p $(PM_SHARED_OBJDIR) -clean: - -rm -f $(OBJ) - -rm -f $(DLLNAME)_$(ARCH).$(SHLIBEXT) -spotless: clean - -rm -rf $(DLL_OBJDIR) - -rm -rf $(WPN_SHARED_OBJDIR) - -rm -rf $(GAME_SHARED_OBJDIR) - -rm -rf $(PM_SHARED_OBJDIR) diff --git a/sdk/dlls/Wxdebug.cpp b/sdk/dlls/Wxdebug.cpp deleted file mode 100644 index 26d0d38..0000000 --- a/sdk/dlls/Wxdebug.cpp +++ /dev/null @@ -1,395 +0,0 @@ -//==========================================================================; -// -// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY -// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR -// PURPOSE. -// -// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved. -// -//--------------------------------------------------------------------------; - - -// For every module and executable we store a debugging level and flags -// for the types of output that are desired. Constants for the types are -// defined in WXDEBUG.H and more can be added. -// The keys are stored in the registry under the -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Type and -// HKEY_LOCAL_MACHINE\SOFTWARE\Debug\\Level key values -// -// There are also global values under SOFTWARE\Debug\Global which are loaded -// after the module-specific values. The Types specified there are OR'ed with -// the module specific types and m_dwLevel is set to the greater of the global -// and the module specific settings. - -#include -#include - -#include "extdll.h" -#include "util.h" -#include "wxdebug.h" - -#include - -#ifdef _DEBUG - -void WINAPI DbgInitModuleName(void); -void WINAPI DbgInitModuleSettings(void); -void WINAPI DbgInitGlobalSettings(void); -void WINAPI DbgInitLogTo(HKEY hKey); -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel); - - - -const INT iDEBUGINFO = 512; // Used to format strings - -HINSTANCE m_hInst; // Module instance handle -TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name -//CRITICAL_SECTION m_CSDebug; // Controls access to list -BOOL m_bInit = FALSE; // Have we been initialised -HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here -DWORD m_dwTypes = 0; -DWORD m_dwLevel = 0; - -const TCHAR *m_pBaseKey = TEXT("SOFTWARE\\Debug"); -const TCHAR *m_pGlobalKey = TEXT("GLOBAL"); -TCHAR *pKeyNames[] = -{ - TEXT("Types"), - TEXT("Level") -}; - - -// DbgInitialize -// This sets the instance handle that the debug library uses to find -// the module's file name from the Win32 GetModuleFileName function -void WINAPI DbgInitialise(HINSTANCE hInst) -{ - if (!m_bInit) - { - //InitializeCriticalSection(&m_CSDebug); - m_bInit = TRUE; - m_hInst = hInst; - DbgInitModuleName(); - DbgInitModuleSettings(); - DbgInitGlobalSettings(); - } -} - - -// DbgTerminate -// This is called to clear up any resources the debug library uses - at the -// moment we delete our critical section and the handle of the output file. -void WINAPI DbgTerminate() -{ - if (m_bInit) - { - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - //DeleteCriticalSection(&m_CSDebug); - m_bInit = FALSE; - } -} - - -// DbgInitModuleName -// Initialise the module file name -void WINAPI DbgInitModuleName() -{ - TCHAR FullName[iDEBUGINFO]; // Load the full path and module name - TCHAR *pName; // Searches from the end for a backslash - - GetModuleFileName(m_hInst,FullName,iDEBUGINFO); - pName = _tcsrchr(FullName,'\\'); - if (pName == NULL) - { - pName = FullName; - } - else - { - pName++; - } - lstrcpy(m_ModuleName,pName); -} - - -// DbgInitModuleSettings -// Retrieve the module-specific settings -void WINAPI DbgInitModuleSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hModuleKey; // Module key handle - - // Construct the base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_ModuleName); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hModuleKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access module key")); - return; - } - - DbgInitLogTo(hModuleKey); - DbgInitKeyLevels(hModuleKey, &m_dwTypes, &m_dwLevel); - RegCloseKey(hModuleKey); -} - - -// DbgInitGlobalSettings -// This is called by DbgInitialize to read the global debug settings for -// Level and Type from the registry. The Types are OR'ed together and m_dwLevel -// is set to the greater of the global and module-specific values. -void WINAPI DbgInitGlobalSettings() -{ - LONG lReturn; // Create key return value - TCHAR szInfo[iDEBUGINFO]; // Constructs key names - HKEY hGlobalKey; // Global override key - DWORD dwTypes = 0; - DWORD dwLevel = 0; - - // Construct the global base key name - wsprintf(szInfo,TEXT("%s\\%s"),m_pBaseKey,m_pGlobalKey); - - // Create or open the key for this module - lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key - szInfo, // Address of subkey name - (DWORD)0, // Reserved value - NULL, // Address of class name - (DWORD)0, // Special options flags - KEY_ALL_ACCESS, // Desired security access - NULL, // Key security descriptor - &hGlobalKey, // Opened handle buffer - NULL); // What really happened - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not access GLOBAL module key")); - return; - } - - DbgInitKeyLevels(hGlobalKey, &dwTypes, &dwLevel); - RegCloseKey(hGlobalKey); - - m_dwTypes |= dwTypes; - if (dwLevel > m_dwLevel) - m_dwLevel = dwLevel; -} - - -// DbgInitLogTo -// Called by DbgInitModuleSettings to setup alternate logging destinations -void WINAPI DbgInitLogTo(HKEY hKey) -{ - LONG lReturn; - DWORD dwKeyType; - DWORD dwKeySize; - TCHAR szFile[MAX_PATH] = {0}; - static const TCHAR cszKey[] = TEXT("LogToFile"); - - dwKeySize = MAX_PATH; - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - cszKey, // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE) szFile, // Returns the field's value - &dwKeySize); // Number of bytes transferred - - // create an empty key if it does not already exist - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ) - { - dwKeySize = 1; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - cszKey, // Address of subkey name - (DWORD) 0, // Reserved field - REG_SZ, // Type of the key field - (PBYTE)szFile, // Value for the field - dwKeySize); // Size of the field buffer - } - - // if an output-to was specified. try to open it. - if (m_hOutput != INVALID_HANDLE_VALUE) - { - DBGASSERTEXECUTE(CloseHandle(m_hOutput)); - m_hOutput = INVALID_HANDLE_VALUE; - } - if (szFile[0] != 0) - { - if (!lstrcmpi(szFile, TEXT("Console"))) - { - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (m_hOutput == INVALID_HANDLE_VALUE) - { - AllocConsole(); - m_hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - } - SetConsoleTitle (TEXT("Valve Debug Output")); - } else if (szFile[0] && - lstrcmpi(szFile, TEXT("Debug")) && - lstrcmpi(szFile, TEXT("Debugger")) && - lstrcmpi(szFile, TEXT("Deb"))) - { - m_hOutput = CreateFile(szFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (INVALID_HANDLE_VALUE != m_hOutput) - { - static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n"); - SetFilePointer (m_hOutput, 0, NULL, FILE_END); - DbgOutString (cszBar); - } - } - } -} - - -// DbgInitKeyLevels -// This is called by DbgInitModuleSettings and DbgInitGlobalSettings to read -// settings for Types and Level from the registry -void WINAPI DbgInitKeyLevels(HKEY hKey, DWORD *pdwTypes, DWORD *pdwLevel) -{ - LONG lReturn; // Create key return value - DWORD dwKeySize; // Size of the key value - DWORD dwKeyType; // Receives it's type - - // Get the Types value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[0], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwTypes, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwTypes = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[0], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwTypes, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[0]); - *pdwTypes = 0; - } - } - - // Get the Level value - dwKeySize = sizeof(DWORD); - lReturn = RegQueryValueEx( - hKey, // Handle to an open key - pKeyNames[1], // Subkey name derivation - NULL, // Reserved field - &dwKeyType, // Returns the field type - (LPBYTE)pdwLevel, // Returns the field's value - &dwKeySize ); // Number of bytes transferred - - // If either the key was not available or it was not a DWORD value - // then we ensure only the high priority debug logging is output - // but we try and update the field to a zero filled DWORD value - - if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) - { - *pdwLevel = 0; - lReturn = RegSetValueEx( - hKey, // Handle of an open key - pKeyNames[1], // Address of subkey name - (DWORD)0, // Reserved field - REG_DWORD, // Type of the key field - (PBYTE)pdwLevel, // Value for the field - sizeof(DWORD)); // Size of the field buffer - - if (lReturn != ERROR_SUCCESS) - { - DbgLogInfo(LOG_ERROR, 0, TEXT("Could not create subkey %s"),pKeyNames[1]); - *pdwLevel = 0; - } - } -} - - -// DbgOutString -void WINAPI DbgOutString(LPCTSTR psz) -{ - if (!m_bInit) - return; - if (m_hOutput != INVALID_HANDLE_VALUE) { - UINT cb = lstrlen(psz); - DWORD dw; - WriteFile (m_hOutput, psz, cb, &dw, NULL); - } else { - OutputDebugString (psz); - } -} - - -// DbgLogInfo -// Print a formatted string to the debugger prefixed with this module's name -// Because the debug code is linked statically every module loaded will -// have its own copy of this code. It therefore helps if the module name is -// included on the output so that the offending code can be easily found -void WINAPI DbgLogInfo(DWORD Type, DWORD Level, const TCHAR *pFormat,...) -{ - if (!m_bInit) - return; - // Check the current level for this type combination */ - if (((Type & m_dwTypes) == 0) || (m_dwLevel < Level)) - return; - - TCHAR szInfo[2000]; - - // Format the variable length parameter list - - va_list va; - va_start(va, pFormat); - - //lstrcpy(szInfo, m_ModuleName); - //lstrcat(szInfo, TEXT(": ")); - wvsprintf(szInfo /* + lstrlen(szInfo) */, pFormat, va); - //lstrcat(szInfo, TEXT("\r\n")); - DbgOutString(szInfo); - - va_end(va); -} - - -// DbgKernelAssert -// If we are executing as a pure kernel filter we cannot display message -// boxes to the user, this provides an alternative which puts the error -// condition on the debugger output with a suitable eye catching message -void WINAPI DbgKernelAssert(const TCHAR *pCondition, const TCHAR *pFileName, INT iLine) -{ - if (!m_bInit) - return; - DbgLogInfo(LOG_ERROR, 0, TEXT(m_ModuleName)); - DbgLogInfo(LOG_ERROR, 0, TEXT(": Assertion FAILED (%s) at line %d in file %s\r\n"), pCondition, iLine, pFileName); - DebugBreak(); -} - -#endif // _DEBUG - - diff --git a/sdk/dlls/activity.h b/sdk/dlls/activity.h deleted file mode 100644 index 1098d48..0000000 --- a/sdk/dlls/activity.h +++ /dev/null @@ -1,109 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef ACTIVITY_H -#define ACTIVITY_H - - -typedef enum { - ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity - ACT_IDLE = 1, - ACT_GUARD, - ACT_WALK, - ACT_RUN, - ACT_FLY, // Fly (and flap if appropriate) - ACT_SWIM, - ACT_HOP, // vertical jump - ACT_LEAP, // long forward jump - ACT_FALL, - ACT_LAND, - ACT_STRAFE_LEFT, - ACT_STRAFE_RIGHT, - ACT_ROLL_LEFT, // tuck and roll, left - ACT_ROLL_RIGHT, // tuck and roll, right - ACT_TURN_LEFT, // turn quickly left (stationary) - ACT_TURN_RIGHT, // turn quickly right (stationary) - ACT_CROUCH, // the act of crouching down from a standing position - ACT_CROUCHIDLE, // holding body in crouched position (loops) - ACT_STAND, // the act of standing from a crouched position - ACT_USE, - ACT_SIGNAL1, - ACT_SIGNAL2, - ACT_SIGNAL3, - ACT_TWITCH, - ACT_COWER, - ACT_SMALL_FLINCH, - ACT_BIG_FLINCH, - ACT_RANGE_ATTACK1, - ACT_RANGE_ATTACK2, - ACT_MELEE_ATTACK1, - ACT_MELEE_ATTACK2, - ACT_RELOAD, - ACT_ARM, // pull out gun, for instance - ACT_DISARM, // reholster gun - ACT_EAT, // monster chowing on a large food item (loop) - ACT_DIESIMPLE, - ACT_DIEBACKWARD, - ACT_DIEFORWARD, - ACT_DIEVIOLENT, - ACT_BARNACLE_HIT, // barnacle tongue hits a monster - ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) - ACT_BARNACLE_CHOMP, // barnacle latches on to the monster - ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) - ACT_SLEEP, - ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor - ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall ) - ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop) - ACT_WALK_HURT, // limp (loop) - ACT_RUN_HURT, // limp (loop) - ACT_HOVER, // Idle while in flight - ACT_GLIDE, // Fly (don't flap) - ACT_FLY_LEFT, // Turn left in flight - ACT_FLY_RIGHT, // Turn right in flight - ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air - ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster - ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops. - ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc ) - ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of - ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever. - ACT_SPECIAL_ATTACK1, // very monster specific special attacks. - ACT_SPECIAL_ATTACK2, - ACT_COMBAT_IDLE, // agitated idle. - ACT_WALK_SCARED, - ACT_RUN_SCARED, - ACT_VICTORY_DANCE, // killed a player, do a victory dance. - ACT_DIE_HEADSHOT, // die, hit in head. - ACT_DIE_CHESTSHOT, // die, hit in chest - ACT_DIE_GUTSHOT, // die, hit in gut - ACT_DIE_BACKSHOT, // die, hit in back - ACT_FLINCH_HEAD, - ACT_FLINCH_CHEST, - ACT_FLINCH_STOMACH, - ACT_FLINCH_LEFTARM, - ACT_FLINCH_RIGHTARM, - ACT_FLINCH_LEFTLEG, - ACT_FLINCH_RIGHTLEG, -} Activity; - - -typedef struct { - int type; - const char *name; -} activity_map_t; - -extern activity_map_t activity_map[]; - - -#endif //ACTIVITY_H diff --git a/sdk/dlls/activitymap.h b/sdk/dlls/activitymap.h deleted file mode 100644 index 5f77c55..0000000 --- a/sdk/dlls/activitymap.h +++ /dev/null @@ -1,97 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#define _A( a ) { a, #a } - -activity_map_t activity_map[] = -{ -_A( ACT_IDLE ), -_A( ACT_GUARD ), -_A( ACT_WALK ), -_A( ACT_RUN ), -_A( ACT_FLY ), -_A( ACT_SWIM ), -_A( ACT_HOP ), -_A( ACT_LEAP ), -_A( ACT_FALL ), -_A( ACT_LAND ), -_A( ACT_STRAFE_LEFT ), -_A( ACT_STRAFE_RIGHT ), -_A( ACT_ROLL_LEFT ), -_A( ACT_ROLL_RIGHT ), -_A( ACT_TURN_LEFT ), -_A( ACT_TURN_RIGHT ), -_A( ACT_CROUCH ), -_A( ACT_CROUCHIDLE ), -_A( ACT_STAND ), -_A( ACT_USE ), -_A( ACT_SIGNAL1 ), -_A( ACT_SIGNAL2 ), -_A( ACT_SIGNAL3 ), -_A( ACT_TWITCH ), -_A( ACT_COWER ), -_A( ACT_SMALL_FLINCH ), -_A( ACT_BIG_FLINCH ), -_A( ACT_RANGE_ATTACK1 ), -_A( ACT_RANGE_ATTACK2 ), -_A( ACT_MELEE_ATTACK1 ), -_A( ACT_MELEE_ATTACK2 ), -_A( ACT_RELOAD ), -_A( ACT_ARM ), -_A( ACT_DISARM ), -_A( ACT_EAT ), -_A( ACT_DIESIMPLE ), -_A( ACT_DIEBACKWARD ), -_A( ACT_DIEFORWARD ), -_A( ACT_DIEVIOLENT ), -_A( ACT_BARNACLE_HIT ), -_A( ACT_BARNACLE_PULL ), -_A( ACT_BARNACLE_CHOMP ), -_A( ACT_BARNACLE_CHEW ), -_A( ACT_SLEEP ), -_A( ACT_INSPECT_FLOOR ), -_A( ACT_INSPECT_WALL ), -_A( ACT_IDLE_ANGRY ), -_A( ACT_WALK_HURT ), -_A( ACT_RUN_HURT ), -_A( ACT_HOVER ), -_A( ACT_GLIDE ), -_A( ACT_FLY_LEFT ), -_A( ACT_FLY_RIGHT ), -_A( ACT_DETECT_SCENT ), -_A( ACT_SNIFF ), -_A( ACT_BITE ), -_A( ACT_THREAT_DISPLAY ), -_A( ACT_FEAR_DISPLAY ), -_A( ACT_EXCITED ), -_A( ACT_SPECIAL_ATTACK1 ), -_A( ACT_SPECIAL_ATTACK2 ), -_A( ACT_COMBAT_IDLE ), -_A( ACT_WALK_SCARED ), -_A( ACT_RUN_SCARED ), -_A( ACT_VICTORY_DANCE ), -_A( ACT_DIE_HEADSHOT ), -_A( ACT_DIE_CHESTSHOT ), -_A( ACT_DIE_GUTSHOT ), -_A( ACT_DIE_BACKSHOT ), -_A( ACT_FLINCH_HEAD ), -_A( ACT_FLINCH_CHEST ), -_A( ACT_FLINCH_STOMACH ), -_A( ACT_FLINCH_LEFTARM ), -_A( ACT_FLINCH_RIGHTARM ), -_A( ACT_FLINCH_LEFTLEG ), -_A( ACT_FLINCH_RIGHTLEG ), -{ 0, NULL } -}; diff --git a/sdk/dlls/aflock.cpp b/sdk/dlls/aflock.cpp deleted file mode 100644 index 7ccd368..0000000 --- a/sdk/dlls/aflock.cpp +++ /dev/null @@ -1,911 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -//========================================================= -#include "archtypes.h" // DAL - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" - -#define AFLOCK_MAX_RECRUIT_RADIUS 1024 -#define AFLOCK_FLY_SPEED 125 -#define AFLOCK_TURN_RATE 75 -#define AFLOCK_ACCELERATE 10 -#define AFLOCK_CHECK_DIST 192 -#define AFLOCK_TOO_CLOSE 100 -#define AFLOCK_TOO_FAR 256 - -//========================================================= -//========================================================= -class CFlockingFlyerFlock : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void SpawnFlock( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Sounds are shared by the flock - static void PrecacheFlockSounds( void ); - - int m_cFlockSize; - float m_flFlockRadius; -}; - -TYPEDESCRIPTION CFlockingFlyerFlock::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyerFlock, m_cFlockSize, FIELD_INTEGER ), - DEFINE_FIELD( CFlockingFlyerFlock, m_flFlockRadius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyerFlock, CBaseMonster ); - -//========================================================= -//========================================================= -class CFlockingFlyer : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SpawnCommonCode( void ); - void EXPORT IdleThink( void ); - void BoidAdvanceFrame( void ); - void EXPORT FormFlock( void ); - void EXPORT Start( void ); - void EXPORT FlockLeaderThink( void ); - void EXPORT FlockFollowerThink( void ); - void EXPORT FallHack( void ); - void MakeSound( void ); - void AlertFlock( void ); - void SpreadFlock( void ); - void SpreadFlock2( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Poop ( void ); - BOOL FPathBlocked( void ); - //void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int IsLeader( void ) { return m_pSquadLeader == this; } - int InSquad( void ) { return m_pSquadLeader != NULL; } - int SquadCount( void ); - void SquadRemove( CFlockingFlyer *pRemove ); - void SquadUnlink( void ); - void SquadAdd( CFlockingFlyer *pAdd ); - void SquadDisband( void ); - - CFlockingFlyer *m_pSquadLeader; - CFlockingFlyer *m_pSquadNext; - BOOL m_fTurning;// is this boid turning? - BOOL m_fCourseAdjust;// followers set this flag TRUE to override flocking while they avoid something - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - Vector m_vecReferencePoint;// last place we saw leader - Vector m_vecAdjustedVelocity;// adjusted velocity (used when fCourseAdjust is TRUE) - float m_flGoalSpeed; - float m_flLastBlockedTime; - float m_flFakeBlockedTime; - float m_flAlertTime; - float m_flFlockNextSoundTime; -}; -LINK_ENTITY_TO_CLASS( monster_flyer, CFlockingFlyer ); -LINK_ENTITY_TO_CLASS( monster_flyer_flock, CFlockingFlyerFlock ); - -TYPEDESCRIPTION CFlockingFlyer::m_SaveData[] = -{ - DEFINE_FIELD( CFlockingFlyer, m_pSquadLeader, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_pSquadNext, FIELD_CLASSPTR ), - DEFINE_FIELD( CFlockingFlyer, m_fTurning, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fCourseAdjust, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CFlockingFlyer, m_vecReferencePoint, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_vecAdjustedVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CFlockingFlyer, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFlockingFlyer, m_flLastBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flFakeBlockedTime, FIELD_TIME ), - DEFINE_FIELD( CFlockingFlyer, m_flAlertTime, FIELD_TIME ), -// DEFINE_FIELD( CFlockingFlyer, m_flFlockNextSoundTime, FIELD_TIME ), // don't need to save -}; - -IMPLEMENT_SAVERESTORE( CFlockingFlyer, CBaseMonster ); - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iFlockSize")) - { - m_cFlockSize = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "flFlockRadius")) - { - m_flFlockRadius = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: Spawn( ) -{ - Precache( ); - SpawnFlock(); - - REMOVE_ENTITY(ENT(pev)); // dump the spawn ent -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: Precache( ) -{ - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); - - PrecacheFlockSounds(); -} - - -void CFlockingFlyerFlock :: PrecacheFlockSounds( void ) -{ - PRECACHE_SOUND("boid/boid_alert1.wav" ); - PRECACHE_SOUND("boid/boid_alert2.wav" ); - - PRECACHE_SOUND("boid/boid_idle1.wav" ); - PRECACHE_SOUND("boid/boid_idle2.wav" ); -} - -//========================================================= -//========================================================= -void CFlockingFlyerFlock :: SpawnFlock( void ) -{ - float R = m_flFlockRadius; - int iCount; - Vector vecSpot; - CFlockingFlyer *pBoid, *pLeader; - - pLeader = pBoid = NULL; - - for ( iCount = 0 ; iCount < m_cFlockSize ; iCount++ ) - { - pBoid = GetClassPtr( (CFlockingFlyer *)NULL ); - - if ( !pLeader ) - { - // make this guy the leader. - pLeader = pBoid; - - pLeader->m_pSquadLeader = pLeader; - pLeader->m_pSquadNext = NULL; - } - - vecSpot.x = RANDOM_FLOAT( -R, R ); - vecSpot.y = RANDOM_FLOAT( -R, R ); - vecSpot.z = RANDOM_FLOAT( 0, 16 ); - vecSpot = pev->origin + vecSpot; - - UTIL_SetOrigin(pBoid->pev, vecSpot); - pBoid->pev->movetype = MOVETYPE_FLY; - pBoid->SpawnCommonCode(); - pBoid->pev->flags &= ~FL_ONGROUND; - pBoid->pev->velocity = g_vecZero; - pBoid->pev->angles = pev->angles; - - pBoid->pev->frame = 0; - pBoid->pev->nextthink = gpGlobals->time + 0.2; - pBoid->SetThink( &CFlockingFlyer :: IdleThink ); - - if ( pBoid != pLeader ) - { - pLeader->SquadAdd( pBoid ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Spawn( ) -{ - Precache( ); - SpawnCommonCode(); - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CFlockingFlyer::IdleThink ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Precache( ) -{ - //PRECACHE_MODEL("models/aflock.mdl"); - PRECACHE_MODEL("models/boid.mdl"); - CFlockingFlyerFlock::PrecacheFlockSounds(); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: MakeSound( void ) -{ - if ( m_flAlertTime > gpGlobals->time ) - { - // make agitated sounds - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_alert2.wav", 1, ATTN_NORM ); break; - } - - return; - } - - // make normal sound - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "boid/boid_idle2.wav", 1, ATTN_NORM ); break; - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CFlockingFlyer *pSquad; - - pSquad = (CFlockingFlyer *)m_pSquadLeader; - - while ( pSquad ) - { - pSquad->m_flAlertTime = gpGlobals->time + 15; - pSquad = (CFlockingFlyer *)pSquad->m_pSquadNext; - } - - if ( m_pSquadLeader ) - { - m_pSquadLeader->SquadRemove( this ); - } - - pev->deadflag = DEAD_DEAD; - - pev->framerate = 0; - pev->effects = EF_NOINTERP; - - UTIL_SetSize( pev, Vector(0,0,0), Vector(0,0,0) ); - pev->movetype = MOVETYPE_TOSS; - - SetThink ( &CFlockingFlyer::FallHack ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CFlockingFlyer :: FallHack( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - if ( !FClassnameIs ( pev->groundentity, "worldspawn" ) ) - { - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->velocity = g_vecZero; - SetThink( NULL ); - } - } -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: SpawnCommonCode( ) -{ - pev->deadflag = DEAD_NO; - pev->classname = MAKE_STRING("monster_flyer"); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->takedamage = DAMAGE_NO; - pev->health = 1; - - m_fPathBlocked = FALSE;// obstacles will be detected - m_flFieldOfView = 0.2; - - //SET_MODEL(ENT(pev), "models/aflock.mdl"); - SET_MODEL(ENT(pev), "models/boid.mdl"); - -// UTIL_SetSize(pev, Vector(0,0,0), Vector(0,0,0)); - UTIL_SetSize(pev, Vector(-5,-5,0), Vector(5,5,2)); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: BoidAdvanceFrame ( ) -{ - float flapspeed = (pev->speed - pev->armorvalue) / AFLOCK_ACCELERATE; - pev->armorvalue = pev->armorvalue * .8 + pev->speed * .2; - - if (flapspeed < 0) flapspeed = -flapspeed; - if (flapspeed < 0.25) flapspeed = 0.25; - if (flapspeed > 1.9) flapspeed = 1.9; - - pev->framerate = flapspeed; - - // lean - pev->avelocity.x = - (pev->angles.x + flapspeed * 5); - - // bank - pev->avelocity.z = - (pev->angles.z + pev->avelocity.y); - - // pev->framerate = flapspeed; - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -//========================================================= -void CFlockingFlyer :: IdleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.2; - - // see if there's a client in the same pvs as the monster - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - SetThink( &CFlockingFlyer::Start ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -//========================================================= -// Start - player enters the pvs, so get things going. -//========================================================= -void CFlockingFlyer :: Start( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( IsLeader() ) - { - SetThink( &CFlockingFlyer::FlockLeaderThink ); - } - else - { - SetThink( &CFlockingFlyer::FlockFollowerThink ); - } - -/* - Vector vecTakeOff; - vecTakeOff = Vector ( 0 , 0 , 0 ); - - vecTakeOff.z = 50 + RANDOM_FLOAT ( 0, 100 ); - vecTakeOff.x = 20 - RANDOM_FLOAT ( 0, 40); - vecTakeOff.y = 20 - RANDOM_FLOAT ( 0, 40); - - pev->velocity = vecTakeOff; - - - pev->speed = pev->velocity.Length(); - pev->sequence = 0; -*/ - SetActivity ( ACT_FLY ); - ResetSequenceInfo( ); - BoidAdvanceFrame( ); - - pev->speed = AFLOCK_FLY_SPEED;// no delay! -} - -//========================================================= -// Leader boid calls this to form a flock from surrounding boids -//========================================================= -void CFlockingFlyer :: FormFlock( void ) -{ - if ( !InSquad() ) - { - // I am my own leader - m_pSquadLeader = this; - m_pSquadNext = NULL; - int squadCount = 1; - - CBaseEntity *pEntity = NULL; - - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, AFLOCK_MAX_RECRUIT_RADIUS )) != NULL) - { - CBaseMonster *pRecruit = pEntity->MyMonsterPointer( ); - - if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) - { - // Can we recruit this guy? - if ( FClassnameIs ( pRecruit->pev, "monster_flyer" ) ) - { - squadCount++; - SquadAdd( (CFlockingFlyer *)pRecruit ); - } - } - } - } - - SetThink( &CFlockingFlyer::IdleThink );// now that flock is formed, go to idle and wait for a player to come along. - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Searches for boids that are too close and pushes them away -//========================================================= -void CFlockingFlyer :: SpreadFlock( ) -{ - Vector vecDir; - float flSpeed;// holds vector magnitude while we fiddle with the direction - - CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) - { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - // push the other away - vecDir = ( pList->pev->origin - pev->origin ); - vecDir = vecDir.Normalize(); - - // store the magnitude of the other boid's velocity, and normalize it so we - // can average in a course that points away from the leader. - flSpeed = pList->pev->velocity.Length(); - pList->pev->velocity = pList->pev->velocity.Normalize(); - pList->pev->velocity = ( pList->pev->velocity + vecDir ) * 0.5; - pList->pev->velocity = pList->pev->velocity * flSpeed; - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// Alters the caller's course if he's too close to others -// -// This function should **ONLY** be called when Caller's velocity is normalized!! -//========================================================= -void CFlockingFlyer :: SpreadFlock2 ( ) -{ - Vector vecDir; - - CFlockingFlyer *pList = m_pSquadLeader; - while ( pList ) - { - if ( pList != this && ( pev->origin - pList->pev->origin ).Length() <= AFLOCK_TOO_CLOSE ) - { - vecDir = ( pev->origin - pList->pev->origin ); - vecDir = vecDir.Normalize(); - - pev->velocity = (pev->velocity + vecDir); - } - - pList = pList->m_pSquadNext; - } -} - -//========================================================= -// FBoidPathBlocked - returns TRUE if there is an obstacle ahead -//========================================================= -BOOL CFlockingFlyer :: FPathBlocked( ) -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - BOOL fBlocked; - - if ( m_flFakeBlockedTime > gpGlobals->time ) - { - m_flLastBlockedTime = gpGlobals->time; - return TRUE; - } - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pevBoid->velocity ); - UTIL_MakeVectors ( pev->angles ); - - fBlocked = FALSE;// assume the way ahead is clear - - // check for obstacle ahead - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - // extra wide checks - UTIL_TraceLine(pev->origin + gpGlobals->v_right * 12, pev->origin + gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - UTIL_TraceLine(pev->origin - gpGlobals->v_right * 12, pev->origin - gpGlobals->v_right * 12 + gpGlobals->v_forward * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - m_flLastBlockedTime = gpGlobals->time; - fBlocked = TRUE; - } - - if ( !fBlocked && gpGlobals->time - m_flLastBlockedTime > 6 ) - { - // not blocked, and it's been a few seconds since we've actually been blocked. - m_flFakeBlockedTime = gpGlobals->time + RANDOM_LONG(1, 3); - } - - return fBlocked; -} - - -//========================================================= -// Leader boids use this think every tenth -//========================================================= -void CFlockingFlyer :: FlockLeaderThink( void ) -{ - TraceResult tr; - Vector vecDist;// used for general measurements - Vector vecDir;// used for general measurements - float flLeftSide; - float flRightSide; - - - pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors ( pev->angles ); - - // is the way ahead clear? - if ( !FPathBlocked () ) - { - // if the boid is turning, stop the trend. - if ( m_fTurning ) - { - m_fTurning = FALSE; - pev->avelocity.y = 0; - } - - m_fPathBlocked = FALSE; - - if (pev->speed <= AFLOCK_FLY_SPEED ) - pev->speed+= 5; - - pev->velocity = gpGlobals->v_forward * pev->speed; - - BoidAdvanceFrame( ); - - return; - } - - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if ( !m_fTurning)// something in the way and boid is not already turning to avoid - { - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flRightSide = vecDist.Length(); - - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flLeftSide = vecDist.Length(); - - // turn right if more clearance on right side - if ( flRightSide > flLeftSide ) - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - // default to left turn :) - else if ( flLeftSide > flRightSide ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - m_fTurning = TRUE; - } - else - { - // equidistant. Pick randomly between left and right. - m_fTurning = TRUE; - - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - pev->avelocity.y = AFLOCK_TURN_RATE; - } - else - { - pev->avelocity.y = -AFLOCK_TURN_RATE; - } - } - } - SpreadFlock( ); - - pev->velocity = gpGlobals->v_forward * pev->speed; - - // check and make sure we aren't about to plow into the ground, don't let it happen - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_up * 16, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0 && pev->velocity.z < 0 ) - pev->velocity.z = 0; - - // maybe it did, though. - if ( FBitSet (pev->flags, FL_ONGROUND) ) - { - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1 ) ); - pev->velocity.z = 0; - } - - if ( m_flFlockNextSoundTime < gpGlobals->time ) - { - MakeSound(); - m_flFlockNextSoundTime = gpGlobals->time + RANDOM_FLOAT( 1, 3 ); - } - - BoidAdvanceFrame( ); - - return; -} - -//========================================================= -// follower boids execute this code when flocking -//========================================================= -void CFlockingFlyer :: FlockFollowerThink( void ) -{ - TraceResult tr; - Vector vecDist; - Vector vecDir; - Vector vecDirToLeader; - float flDistToLeader; - - pev->nextthink = gpGlobals->time + 0.1; - - if ( IsLeader() || !InSquad() ) - { - // the leader has been killed and this flyer suddenly finds himself the leader. - SetThink ( &CFlockingFlyer::FlockLeaderThink ); - return; - } - - vecDirToLeader = ( m_pSquadLeader->pev->origin - pev->origin ); - flDistToLeader = vecDirToLeader.Length(); - - // match heading with leader - pev->angles = m_pSquadLeader->pev->angles; - - // - // We can see the leader, so try to catch up to it - // - if ( FInViewCone ( m_pSquadLeader ) ) - { - // if we're too far away, speed up - if ( flDistToLeader > AFLOCK_TOO_FAR ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 1.5; - } - - // if we're too close, slow down - else if ( flDistToLeader < AFLOCK_TOO_CLOSE ) - { - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - } - else - { - // wait up! the leader isn't out in front, so we slow down to let him pass - m_flGoalSpeed = m_pSquadLeader->pev->velocity.Length() * 0.5; - } - - SpreadFlock2(); - - pev->speed = pev->velocity.Length(); - pev->velocity = pev->velocity.Normalize(); - - // if we are too far from leader, average a vector towards it into our current velocity - if ( flDistToLeader > AFLOCK_TOO_FAR ) - { - vecDirToLeader = vecDirToLeader.Normalize(); - pev->velocity = (pev->velocity + vecDirToLeader) * 0.5; - } - - // clamp speeds and handle acceleration - if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 ) - { - m_flGoalSpeed = AFLOCK_FLY_SPEED * 2; - } - - if ( pev->speed < m_flGoalSpeed ) - { - pev->speed += AFLOCK_ACCELERATE; - } - else if ( pev->speed > m_flGoalSpeed ) - { - pev->speed -= AFLOCK_ACCELERATE; - } - - pev->velocity = pev->velocity * pev->speed; - - BoidAdvanceFrame( ); -} - -/* - // Is this boid's course blocked? - if ( FBoidPathBlocked (pev) ) - { - // course is still blocked from last time. Just keep flying along adjusted - // velocity - if ( m_fCourseAdjust ) - { - pev->velocity = m_vecAdjustedVelocity * pev->speed; - return; - } - else // set course adjust flag and calculate adjusted velocity - { - m_fCourseAdjust = TRUE; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //vecDir = UTIL_VecToAngles( pev->velocity ); - //UTIL_MakeVectors ( vecDir ); - - UTIL_MakeVectors ( pev->angles ); - - // measure clearance on left and right to pick the best dir to turn - UTIL_TraceLine(pev->origin, pev->origin + gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flRightSide = vecDist.Length(); - - UTIL_TraceLine(pev->origin, pev->origin - gpGlobals->v_right * AFLOCK_CHECK_DIST, ignore_monsters, ENT(pev), &tr); - vecDist = (tr.vecEndPos - pev->origin); - flLeftSide = vecDist.Length(); - - // slide right if more clearance on right side - if ( flRightSide > flLeftSide ) - { - m_vecAdjustedVelocity = gpGlobals->v_right; - } - // else slide left - else - { - m_vecAdjustedVelocity = gpGlobals->v_right * -1; - } - } - return; - } - - // if we make it this far, boids path is CLEAR! - m_fCourseAdjust = FALSE; -*/ - - -//========================================================= -// -// SquadUnlink(), Unlink the squad pointers. -// -//========================================================= -void CFlockingFlyer :: SquadUnlink( void ) -{ - m_pSquadLeader = NULL; - m_pSquadNext = NULL; -} - -//========================================================= -// -// SquadAdd(), add pAdd to my squad -// -//========================================================= -void CFlockingFlyer :: SquadAdd( CFlockingFlyer *pAdd ) -{ - ASSERT( pAdd!=NULL ); - ASSERT( !pAdd->InSquad() ); - ASSERT( this->IsLeader() ); - - pAdd->m_pSquadNext = m_pSquadNext; - m_pSquadNext = pAdd; - pAdd->m_pSquadLeader = this; -} -//========================================================= -// -// SquadRemove(), remove pRemove from my squad. -// If I am pRemove, promote m_pSquadNext to leader -// -//========================================================= -void CFlockingFlyer :: SquadRemove( CFlockingFlyer *pRemove ) -{ - ASSERT( pRemove!=NULL ); - ASSERT( this->IsLeader() ); - ASSERT( pRemove->m_pSquadLeader == this ); - - if ( SquadCount() > 2 ) - { - // Removing the leader, promote m_pSquadNext to leader - if ( pRemove == this ) - { - CFlockingFlyer *pLeader = m_pSquadNext; - - // copy the enemy LKP to the new leader - pLeader->m_vecEnemyLKP = m_vecEnemyLKP; - - if ( pLeader ) - { - CFlockingFlyer *pList = pLeader; - - while ( pList ) - { - pList->m_pSquadLeader = pLeader; - pList = pList->m_pSquadNext; - } - - } - SquadUnlink(); - } - else // removing a node - { - CFlockingFlyer *pList = this; - - // Find the node before pRemove - while ( pList->m_pSquadNext != pRemove ) - { - // assert to test valid list construction - ASSERT( pList->m_pSquadNext != NULL ); - pList = pList->m_pSquadNext; - } - // List validity - ASSERT( pList->m_pSquadNext == pRemove ); - - // Relink without pRemove - pList->m_pSquadNext = pRemove->m_pSquadNext; - - // Unlink pRemove - pRemove->SquadUnlink(); - } - } - else - SquadDisband(); -} -//========================================================= -// -// SquadCount(), return the number of members of this squad -// callable from leaders & followers -// -//========================================================= -int CFlockingFlyer :: SquadCount( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - int squadCount = 0; - while ( pList ) - { - squadCount++; - pList = pList->m_pSquadNext; - } - - return squadCount; -} - -//========================================================= -// -// SquadDisband(), Unlink all squad members -// -//========================================================= -void CFlockingFlyer :: SquadDisband( void ) -{ - CFlockingFlyer *pList = m_pSquadLeader; - CFlockingFlyer *pNext; - - while ( pList ) - { - pNext = pList->m_pSquadNext; - pList->SquadUnlink(); - pList = pNext; - } -} diff --git a/sdk/dlls/agrunt.cpp b/sdk/dlls/agrunt.cpp deleted file mode 100644 index c84b1a5..0000000 --- a/sdk/dlls/agrunt.cpp +++ /dev/null @@ -1,1188 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Agrunt - Dominant, warlike alien grunt monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_AGRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_AGRUNT_THREAT_DISPLAY, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_AGRUNT_SETUP_HIDE_ATTACK = LAST_COMMON_TASK + 1, - TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, -}; - -int iAgruntMuzzleFlash; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define AGRUNT_AE_HORNET1 ( 1 ) -#define AGRUNT_AE_HORNET2 ( 2 ) -#define AGRUNT_AE_HORNET3 ( 3 ) -#define AGRUNT_AE_HORNET4 ( 4 ) -#define AGRUNT_AE_HORNET5 ( 5 ) -// some events are set up in the QC file that aren't recognized by the code yet. -#define AGRUNT_AE_PUNCH ( 6 ) -#define AGRUNT_AE_BITE ( 7 ) - -#define AGRUNT_AE_LEFT_FOOT ( 10 ) -#define AGRUNT_AE_RIGHT_FOOT ( 11 ) - -#define AGRUNT_AE_LEFT_PUNCH ( 12 ) -#define AGRUNT_AE_RIGHT_PUNCH ( 13 ) - - - -#define AGRUNT_MELEE_DIST 100 - -class CAGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -32, -32, 0 ); - pev->absmax = pev->origin + Vector( 32, 32, 85 ); - } - - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - BOOL FCanCheckAttacks ( void ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - void StartTask ( Task_t *pTask ); - void AlertSound( void ); - void DeathSound ( void ); - void PainSound ( void ); - void AttackSound ( void ); - void PrescheduleThink ( void ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int IRelationship( CBaseEntity *pTarget ); - void StopTalking ( void ); - BOOL ShouldSpeak( void ); - CUSTOM_SCHEDULES; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pAttackSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - - BOOL m_fCanHornetAttack; - float m_flNextHornetAttackCheck; - - float m_flNextPainTime; - - // three hacky fields for speech stuff. These don't really need to be saved. - float m_flNextSpeakTime; - float m_flNextWordTime; - int m_iLastWord; -}; -LINK_ENTITY_TO_CLASS( monster_alien_grunt, CAGrunt ); - -TYPEDESCRIPTION CAGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CAGrunt, m_fCanHornetAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CAGrunt, m_flNextHornetAttackCheck, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextPainTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextSpeakTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_flNextWordTime, FIELD_TIME ), - DEFINE_FIELD( CAGrunt, m_iLastWord, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CAGrunt, CSquadMonster ); - -const char *CAGrunt::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CAGrunt::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CAGrunt::pAttackSounds[] = -{ - "agrunt/ag_attack1.wav", - "agrunt/ag_attack2.wav", - "agrunt/ag_attack3.wav", -}; - -const char *CAGrunt::pDieSounds[] = -{ - "agrunt/ag_die1.wav", - "agrunt/ag_die4.wav", - "agrunt/ag_die5.wav", -}; - -const char *CAGrunt::pPainSounds[] = -{ - "agrunt/ag_pain1.wav", - "agrunt/ag_pain2.wav", - "agrunt/ag_pain3.wav", - "agrunt/ag_pain4.wav", - "agrunt/ag_pain5.wav", -}; - -const char *CAGrunt::pIdleSounds[] = -{ - "agrunt/ag_idle1.wav", - "agrunt/ag_idle2.wav", - "agrunt/ag_idle3.wav", - "agrunt/ag_idle4.wav", -}; - -const char *CAGrunt::pAlertSounds[] = -{ - "agrunt/ag_alert1.wav", - "agrunt/ag_alert3.wav", - "agrunt/ag_alert4.wav", - "agrunt/ag_alert5.wav", -}; - -//========================================================= -// IRelationship - overridden because Human Grunts are -// Alien Grunt's nemesis. -//========================================================= -int CAGrunt::IRelationship ( CBaseEntity *pTarget ) -{ - if ( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) - { - return R_NM; - } - - return CSquadMonster :: IRelationship( pTarget ); -} - -//========================================================= -// ISoundMask -//========================================================= -int CAGrunt :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// TraceAttack -//========================================================= -void CAGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - Vector vecTracerDir = vecDir; - - vecTracerDir.x += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.y += RANDOM_FLOAT( -0.3, 0.3 ); - vecTracerDir.z += RANDOM_FLOAT( -0.3, 0.3 ); - - vecTracerDir = vecTracerDir * -512; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, ptr->vecEndPos ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( vecTracerDir.x ); - WRITE_COORD( vecTracerDir.y ); - WRITE_COORD( vecTracerDir.z ); - MESSAGE_END(); - } - - flDamage -= 20; - if (flDamage <= 0) - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else - { - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -//========================================================= -// StopTalking - won't speak again for 10-20 seconds. -//========================================================= -void CAGrunt::StopTalking( void ) -{ - m_flNextWordTime = m_flNextSpeakTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); -} - -//========================================================= -// ShouldSpeak - Should this agrunt be talking? -//========================================================= -BOOL CAGrunt::ShouldSpeak( void ) -{ - if ( m_flNextSpeakTime > gpGlobals->time ) - { - // my time to talk is still in the future. - return FALSE; - } - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // if gagged, don't talk outside of combat. - // if not going to talk because of this, put the talk time - // into the future a bit, so we don't talk immediately after - // going into combat - m_flNextSpeakTime = gpGlobals->time + 3; - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CAGrunt :: PrescheduleThink ( void ) -{ - if ( ShouldSpeak() ) - { - if ( m_flNextWordTime < gpGlobals->time ) - { - int num = -1; - - do - { - num = RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1); - } while( num == m_iLastWord ); - - m_iLastWord = num; - - // play a new sound - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pIdleSounds[ num ], 1.0, ATTN_NORM ); - - // is this word our last? - if ( RANDOM_LONG( 1, 10 ) <= 1 ) - { - // stop talking. - StopTalking(); - } - else - { - m_flNextWordTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 1 ); - } - } - } -} - -//========================================================= -// DieSound -//========================================================= -void CAGrunt :: DeathSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0,ARRAYSIZE(pDieSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// AlertSound -//========================================================= -void CAGrunt :: AlertSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// AttackSound -//========================================================= -void CAGrunt :: AttackSound ( void ) -{ - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pAttackSounds[RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// PainSound -//========================================================= -void CAGrunt :: PainSound ( void ) -{ - if ( m_flNextPainTime > gpGlobals->time ) - { - return; - } - - m_flNextPainTime = gpGlobals->time + 0.6; - - StopTalking(); - - EMIT_SOUND ( ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1)], 1.0, ATTN_NORM ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CAGrunt :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CAGrunt :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 110; - break; - default: ys = 100; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CAGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case AGRUNT_AE_HORNET1: - case AGRUNT_AE_HORNET2: - case AGRUNT_AE_HORNET3: - case AGRUNT_AE_HORNET4: - case AGRUNT_AE_HORNET5: - { - // m_vecEnemyLKP should be center of enemy body - Vector vecArmPos, vecArmDir; - Vector vecDirToEnemy; - Vector angDir; - - if (HasConditions( bits_COND_SEE_ENEMY)) - { - vecDirToEnemy = ( ( m_vecEnemyLKP ) - pev->origin ); - angDir = UTIL_VecToAngles( vecDirToEnemy ); - vecDirToEnemy = vecDirToEnemy.Normalize(); - } - else - { - angDir = pev->angles; - UTIL_MakeAimVectors( angDir ); - vecDirToEnemy = gpGlobals->v_forward; - } - - pev->effects = EF_MUZZLEFLASH; - - // make angles +-180 - if (angDir.x > 180) - { - angDir.x = angDir.x - 360; - } - - SetBlending( 0, angDir.x ); - GetAttachment( 0, vecArmPos, vecArmDir ); - - vecArmPos = vecArmPos + vecDirToEnemy * 32; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecArmPos ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecArmPos.x ); // pos - WRITE_COORD( vecArmPos.y ); - WRITE_COORD( vecArmPos.z ); - WRITE_SHORT( iAgruntMuzzleFlash ); // model - WRITE_BYTE( 6 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", vecArmPos, UTIL_VecToAngles( vecDirToEnemy ), edict() ); - UTIL_MakeVectors ( pHornet->pev->angles ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - - - switch ( RANDOM_LONG ( 0 , 2 ) ) - { - case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire1.wav", 1.0, ATTN_NORM, 0, 100 ); break; - case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire2.wav", 1.0, ATTN_NORM, 0, 100 ); break; - case 2: EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, "agrunt/ag_fire3.wav", 1.0, ATTN_NORM, 0, 100 ); break; - } - - CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer(); - - if ( pHornetMonster ) - { - pHornetMonster->m_hEnemy = m_hEnemy; - } - } - break; - - case AGRUNT_AE_LEFT_FOOT: - switch (RANDOM_LONG(0,1)) - { - // left foot - case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder2.wav", 1, ATTN_NORM, 0, 70 ); break; - case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder4.wav", 1, ATTN_NORM, 0, 70 ); break; - } - break; - case AGRUNT_AE_RIGHT_FOOT: - // right foot - switch (RANDOM_LONG(0,1)) - { - case 0: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder1.wav", 1, ATTN_NORM, 0, 70 ); break; - case 1: EMIT_SOUND_DYN ( ENT(pev), CHAN_BODY, "player/pl_ladder3.wav", 1, ATTN_NORM, 0 ,70); break; - } - break; - - case AGRUNT_AE_LEFT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if ( pHurt ) - { - pHurt->pev->punchangle.y = -25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if ( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 250; - } - - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - case AGRUNT_AE_RIGHT_PUNCH: - { - CBaseEntity *pHurt = CheckTraceHullAttack( AGRUNT_MELEE_DIST, gSkillData.agruntDmgPunch, DMG_CLUB ); - - if ( pHurt ) - { - pHurt->pev->punchangle.y = 25; - pHurt->pev->punchangle.x = 8; - - // OK to use gpGlobals without calling MakeVectors, cause CheckTraceHullAttack called it above. - if ( pHurt->IsPlayer() ) - { - // this is a player. Knock him around. - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -250; - } - - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - Vector vecArmPos, vecArmAng; - GetAttachment( 0, vecArmPos, vecArmAng ); - SpawnBlood(vecArmPos, pHurt->BloodColor(), 25);// a little surface blood. - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CAGrunt :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/agrunt.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.agruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = 0; - m_afCapability |= bits_CAP_SQUAD; - - m_HackedGunPos = Vector( 24, 64, 48 ); - - m_flNextSpeakTime = m_flNextWordTime = gpGlobals->time + 10 + RANDOM_LONG(0, 10); - - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CAGrunt :: Precache() -{ - size_t i; - - PRECACHE_MODEL("models/agrunt.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pDieSounds ); i++ ) - PRECACHE_SOUND((char *)pDieSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - - PRECACHE_SOUND( "hassault/hw_shoot1.wav" ); - - iAgruntMuzzleFlash = PRECACHE_MODEL( "sprites/muz4.spr" ); - - UTIL_PrecacheOther( "hornet" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntFail[] = -{ - { - tlAGruntFail, - ARRAYSIZE ( tlAGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Fail" - }, -}; - -//========================================================= -// Combat Fail Schedule -//========================================================= -Task_t tlAGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slAGruntCombatFail[] = -{ - { - tlAGruntCombatFail, - ARRAYSIZE ( tlAGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AGrunt Combat Fail" - }, -}; - -//========================================================= -// Standoff schedule. Used in combat when a monster is -// hiding in cover or the enemy has moved out of sight. -// Should we look around in this schedule? -//========================================================= -Task_t tlAGruntStandoff[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, -}; - -Schedule_t slAGruntStandoff[] = -{ - { - tlAGruntStandoff, - ARRAYSIZE ( tlAGruntStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Agrunt Standoff" - } -}; - -//========================================================= -// Suppress -//========================================================= -Task_t tlAGruntSuppressHornet[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntSuppress[] = -{ - { - tlAGruntSuppressHornet, - ARRAYSIZE ( tlAGruntSuppressHornet ), - 0, - 0, - "AGrunt Suppress Hornet", - }, -}; - -//========================================================= -// primary range attacks -//========================================================= -Task_t tlAGruntRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slAGruntRangeAttack1[] = -{ - { - tlAGruntRangeAttack1, - ARRAYSIZE ( tlAGruntRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE, - - 0, - "AGrunt Range Attack1" - }, -}; - - -Task_t tlAGruntHiddenRangeAttack1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_STANDOFF }, - { TASK_AGRUNT_SETUP_HIDE_ATTACK, 0 }, - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, 0 }, - { TASK_RANGE_ATTACK1_NOTURN, (float)0 }, -}; - -Schedule_t slAGruntHiddenRangeAttack[] = -{ - { - tlAGruntHiddenRangeAttack1, - ARRAYSIZE ( tlAGruntHiddenRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AGrunt Hidden Range Attack1" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAGruntTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAGruntTakeCoverFromEnemy[] = -{ - { - tlAGruntTakeCoverFromEnemy, - ARRAYSIZE ( tlAGruntTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY, - 0, - "AGruntTakeCoverFromEnemy" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlAGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_AGRUNT_THREAT_DISPLAY }, - { TASK_WAIT, (float)0.2 }, - { TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, -}; - -Schedule_t slAGruntVictoryDance[] = -{ - { - tlAGruntVictoryDance, - ARRAYSIZE ( tlAGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "AGruntVictoryDance" - }, -}; - -//========================================================= -//========================================================= -Task_t tlAGruntThreatDisplay[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_THREAT_DISPLAY }, -}; - -Schedule_t slAGruntThreatDisplay[] = -{ - { - tlAGruntThreatDisplay, - ARRAYSIZE ( tlAGruntThreatDisplay ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - - bits_SOUND_PLAYER | - bits_SOUND_COMBAT | - bits_SOUND_WORLD, - "AGruntThreatDisplay" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CAGrunt ) -{ - slAGruntFail, - slAGruntCombatFail, - slAGruntStandoff, - slAGruntSuppress, - slAGruntRangeAttack1, - slAGruntHiddenRangeAttack, - slAGruntTakeCoverFromEnemy, - slAGruntVictoryDance, - slAGruntThreatDisplay, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CAGrunt, CSquadMonster ); - -//========================================================= -// FCanCheckAttacks - this is overridden for alien grunts -// because they can use their smart weapons against unseen -// enemies. Base class doesn't attack anyone it can't see. -//========================================================= -BOOL CAGrunt :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// CheckMeleeAttack1 - alien grunts zap the crap out of -// any enemy that gets too close. -//========================================================= -BOOL CAGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( HasConditions ( bits_COND_SEE_ENEMY ) && flDist <= AGRUNT_MELEE_DIST && flDot >= 0.6 && m_hEnemy != 0 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 -// -// !!!LATER - we may want to load balance this. Several -// tracelines are done, so we may not want to do this every -// server frame. Definitely not while firing. -//========================================================= -BOOL CAGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( gpGlobals->time < m_flNextHornetAttackCheck ) - { - return m_fCanHornetAttack; - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) && flDist >= AGRUNT_MELEE_DIST && flDist <= 1024 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - Vector vecArmPos, vecArmDir; - - // verify that a shot fired from the gun will hit the enemy before the world. - // !!!LATER - we may wish to do something different for projectile weapons as opposed to instant-hit - UTIL_MakeVectors( pev->angles ); - GetAttachment( 0, vecArmPos, vecArmDir ); -// UTIL_TraceLine( vecArmPos, vecArmPos + gpGlobals->v_forward * 256, ignore_monsters, ENT(pev), &tr); - UTIL_TraceLine( vecArmPos, m_hEnemy->BodyTarget(vecArmPos), dont_ignore_monsters, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 || tr.pHit == m_hEnemy->edict() ) - { - m_flNextHornetAttackCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - m_fCanHornetAttack = TRUE; - return m_fCanHornetAttack; - } - } - - m_flNextHornetAttackCheck = gpGlobals->time + 0.2;// don't check for half second if this check wasn't successful - m_fCanHornetAttack = FALSE; - return m_fCanHornetAttack; -} - -//========================================================= -// StartTask -//========================================================= -void CAGrunt :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_AGRUNT_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 50, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "AGruntGetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - - case TASK_AGRUNT_SETUP_HIDE_ATTACK: - // alien grunt shoots hornets back out into the open from a concealed location. - // try to find a spot to throw that gives the smart weapon a good chance of finding the enemy. - // ideally, this spot is along a line that is perpendicular to a line drawn from the agrunt to the enemy. - - CBaseMonster *pEnemyMonsterPtr; - - pEnemyMonsterPtr = m_hEnemy->MyMonsterPointer(); - - if ( pEnemyMonsterPtr ) - { - Vector vecCenter; - TraceResult tr; - BOOL fSkip; - - fSkip = FALSE; - vecCenter = Center(); - - UTIL_VecToAngles( m_vecEnemyLKP - pev->origin ); - - UTIL_TraceLine( Center() + gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin + gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 128, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin - gpGlobals->v_right * 128 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() + gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin + gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - UTIL_TraceLine( Center() - gpGlobals->v_forward * 256, m_vecEnemyLKP, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction == 1.0 ) - { - MakeIdealYaw ( pev->origin - gpGlobals->v_right * 256 ); - fSkip = TRUE; - TaskComplete(); - } - } - - if ( !fSkip ) - { - TaskFail(); - } - } - else - { - ALERT ( at_aiconsole, "AGRunt - no enemy monster ptr!!!\n" ); - TaskFail(); - } - break; - - default: - CSquadMonster :: StartTask ( pTask ); - break; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CAGrunt :: GetSchedule ( void ) -{ - if ( HasConditions(bits_COND_HEAR_SOUND) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - // dangerous sound nearby! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType( SCHED_WAKE_ANGRY ); - } - - // zap player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - AttackSound();// this is a total hack. Should be parto f the schedule - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // can attack - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot ( bits_SLOTS_AGRUNT_HORNET ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( OccupySlot ( bits_SLOT_AGRUNT_CHASE ) ) - { - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); - } - - return GetScheduleOfType ( SCHED_STANDOFF ); - } - default: - break; - } - - return CSquadMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CAGrunt :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - return &slAGruntTakeCoverFromEnemy[ 0 ]; - break; - - case SCHED_RANGE_ATTACK1: - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - { - //normal attack - return &slAGruntRangeAttack1[ 0 ]; - } - else - { - // attack an unseen enemy - // return &slAGruntHiddenRangeAttack[ 0 ]; - return &slAGruntRangeAttack1[ 0 ]; - } - break; - - case SCHED_AGRUNT_THREAT_DISPLAY: - return &slAGruntThreatDisplay[ 0 ]; - break; - - case SCHED_AGRUNT_SUPPRESS: - return &slAGruntSuppress[ 0 ]; - break; - - case SCHED_STANDOFF: - return &slAGruntStandoff[ 0 ]; - break; - - case SCHED_VICTORY_DANCE: - return &slAGruntVictoryDance[ 0 ]; - break; - - case SCHED_FAIL: - // no fail schedule specified, so pick a good generic one. - { - if ( m_hEnemy != 0 ) - { - // I have an enemy - // !!!LATER - what if this enemy is really far away and i'm chasing him? - // this schedule will make me stop, face his last known position for 2 - // seconds, and then try to move again - return &slAGruntCombatFail[ 0 ]; - } - - return &slAGruntFail[ 0 ]; - } - break; - - } - - return CSquadMonster :: GetScheduleOfType( Type ); -} - diff --git a/sdk/dlls/airtank.cpp b/sdk/dlls/airtank.cpp deleted file mode 100644 index 9a91402..0000000 --- a/sdk/dlls/airtank.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -class CAirtank : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT TankThink( void ); - void EXPORT TankTouch( CBaseEntity *pOther ); - int BloodColor( void ) { return DONT_BLEED; }; - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_state; -}; - - -LINK_ENTITY_TO_CLASS( item_airtank, CAirtank ); -TYPEDESCRIPTION CAirtank::m_SaveData[] = -{ - DEFINE_FIELD( CAirtank, m_state, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CAirtank, CGrenade ); - - -void CAirtank :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_oxygen.mdl"); - UTIL_SetSize(pev, Vector( -16, -16, 0), Vector(16, 16, 36)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CAirtank::TankTouch ); - SetThink( &CAirtank::TankThink ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - pev->health = 20; - pev->dmg = 50; - m_state = 1; -} - -void CAirtank::Precache( void ) -{ - PRECACHE_MODEL("models/w_oxygen.mdl"); - PRECACHE_SOUND("doors/aliendoor3.wav"); -} - - -void CAirtank :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->owner = ENT( pevAttacker ); - - // UNDONE: this should make a big bubble cloud, not an explosion - - Explode( pev->origin, Vector( 0, 0, -1 ) ); -} - - -void CAirtank::TankThink( void ) -{ - // Fire trigger - m_state = 1; - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - -void CAirtank::TankTouch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - return; - - if (!m_state) - { - // "no oxygen" sound - EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 1.0, ATTN_NORM ); - return; - } - - // give player 12 more seconds of air - pOther->pev->air_finished = gpGlobals->time + 12; - - // suit recharge sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "doors/aliendoor3.wav", 1.0, ATTN_NORM ); - - // recharge airtank in 30 seconds - pev->nextthink = gpGlobals->time + 30; - m_state = 0; - SUB_UseTargets( this, USE_TOGGLE, 1 ); -} diff --git a/sdk/dlls/animating.cpp b/sdk/dlls/animating.cpp deleted file mode 100644 index 808cdd2..0000000 --- a/sdk/dlls/animating.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== monsters.cpp ======================================================== - - Monster-related utility code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "animation.h" -#include "saverestore.h" - -TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMonster, m_flFrameRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flGroundSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flLastEventCheck, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_fSequenceFinished, FIELD_BOOLEAN ), - DEFINE_FIELD( CBaseMonster, m_fSequenceLoops, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ); - - -//========================================================= -// StudioFrameAdvance - advance the animation frame up to the current time -// if an flInterval is passed in, only advance animation that number of seconds -//========================================================= -float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) -{ - if (flInterval == 0.0) - { - flInterval = (gpGlobals->time - pev->animtime); - if (flInterval <= 0.001) - { - pev->animtime = gpGlobals->time; - return 0.0; - } - } - if (! pev->animtime) - flInterval = 0.0; - - pev->frame += flInterval * m_flFrameRate * pev->framerate; - pev->animtime = gpGlobals->time; - - if (pev->frame < 0.0 || pev->frame >= 256.0) - { - if (m_fSequenceLoops) - pev->frame -= (int)(pev->frame / 256.0) * 256.0; - else - pev->frame = (pev->frame < 0.0) ? 0 : 255; - m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents - } - - return flInterval; -} - -//========================================================= -// LookupActivity -//========================================================= -int CBaseAnimating :: LookupActivity ( int activity ) -{ - ASSERT( activity != 0 ); - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivity( pmodel, pev, activity ); -} - -//========================================================= -// LookupActivityHeaviest -// -// Get activity with highest 'weight' -// -//========================================================= -int CBaseAnimating :: LookupActivityHeaviest ( int activity ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupActivityHeaviest( pmodel, pev, activity ); -} - -//========================================================= -//========================================================= -int CBaseAnimating :: LookupSequence ( const char *label ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::LookupSequence( pmodel, label ); -} - - -//========================================================= -//========================================================= -void CBaseAnimating :: ResetSequenceInfo ( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); - m_fSequenceLoops = ((GetSequenceFlags() & STUDIO_LOOPING) != 0); - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; - m_fSequenceFinished = FALSE; - m_flLastEventCheck = gpGlobals->time; -} - - - -//========================================================= -//========================================================= -BOOL CBaseAnimating :: GetSequenceFlags( ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::GetSequenceFlags( pmodel, pev ); -} - -//========================================================= -// DispatchAnimEvents -//========================================================= -void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) -{ - MonsterEvent_t event; - - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if ( !pmodel ) - { - ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); - return; - } - - // FIXME: I have to do this or some events get missed, and this is probably causing the problem below - flInterval = 0.1; - - // FIX: this still sometimes hits events twice - float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate; - float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate; - m_flLastEventCheck = pev->animtime + flInterval; - - m_fSequenceFinished = FALSE; - if (flEnd >= 256 || flEnd <= 0.0) - m_fSequenceFinished = TRUE; - - int index = 0; - - while ( (index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) - { - HandleAnimEvent( &event ); - } -} - - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBoneController ( int iController, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return SetController( pmodel, pev, iController, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: InitBoneControllers ( void ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - SetController( pmodel, pev, 0, 0.0 ); - SetController( pmodel, pev, 1, 0.0 ); - SetController( pmodel, pev, 2, 0.0 ); - SetController( pmodel, pev, 3, 0.0 ); -} - -//========================================================= -//========================================================= -float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - return ::SetBlending( pmodel, pev, iBlender, flValue ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) -{ - GET_BONE_POSITION( ENT(pev), iBone, origin, angles ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) -{ - GET_ATTACHMENT( ENT(pev), iAttachment, origin, angles ); -} - -//========================================================= -//========================================================= -int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) -{ - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - if (piDir == NULL) - { - int iDir; - int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); - if (iDir != 1) - return -1; - else - return sequence; - } - - return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir ); -} - -//========================================================= -//========================================================= -void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) -{ - -} - -void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) -{ - ::SetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup, iValue ); -} - -int CBaseAnimating :: GetBodygroup( int iGroup ) -{ - return ::GetBodygroup( GET_MODEL_PTR( ENT(pev) ), pev, iGroup ); -} - - -int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs ) -{ - return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); -} - -//========================================================= -//========================================================= - -void CBaseAnimating :: SetSequenceBox( void ) -{ - Vector mins, maxs; - - // Get sequence bbox - if ( ExtractBbox( pev->sequence, mins, maxs ) ) - { - // expand box for rotation - // find min / max for rotations - float yaw = pev->angles.y * (M_PI / 180.0); - - Vector xvector, yvector; - xvector.x = cos(yaw); - xvector.y = sin(yaw); - yvector.x = -sin(yaw); - yvector.y = cos(yaw); - Vector bounds[2]; - - bounds[0] = mins; - bounds[1] = maxs; - - Vector rmin( 9999, 9999, 9999 ); - Vector rmax( -9999, -9999, -9999 ); - Vector base, transformed; - - for (int i = 0; i <= 1; i++ ) - { - base.x = bounds[i].x; - for ( int j = 0; j <= 1; j++ ) - { - base.y = bounds[j].y; - for ( int k = 0; k <= 1; k++ ) - { - base.z = bounds[k].z; - - // transform the point - transformed.x = xvector.x*base.x + yvector.x*base.y; - transformed.y = xvector.y*base.x + yvector.y*base.y; - transformed.z = base.z; - - if (transformed.x < rmin.x) - rmin.x = transformed.x; - if (transformed.x > rmax.x) - rmax.x = transformed.x; - if (transformed.y < rmin.y) - rmin.y = transformed.y; - if (transformed.y > rmax.y) - rmax.y = transformed.y; - if (transformed.z < rmin.z) - rmin.z = transformed.z; - if (transformed.z > rmax.z) - rmax.z = transformed.z; - } - } - } - rmin.z = 0; - rmax.z = rmin.z + 1; - UTIL_SetSize( pev, rmin, rmax ); - } -} - diff --git a/sdk/dlls/animation.cpp b/sdk/dlls/animation.cpp deleted file mode 100644 index e80ccd5..0000000 --- a/sdk/dlls/animation.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include -#include -#include - -#if defined _MSC_VER && _MSC_VER >= 1400 - #ifndef _CRT_SECURE_NO_DEPRECATE - #define _CRT_SECURE_NO_DEPRECATE - #endif - - #pragma warning(disable: 4996) // deprecated functions -#endif - -#include "../common/nowin.h" - -typedef int BOOL; -#define TRUE 1 -#define FALSE 0 - -// hack into header files that we can ship -typedef int qboolean; -typedef unsigned char byte; -#include "../utils/common/mathlib.h" -#include "const.h" -#include "progdefs.h" -#include "edict.h" -#include "eiface.h" - -#include "studio.h" - -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#include "activitymap.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SCRIPTEVENT_H -#include "scriptevent.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif - -extern globalvars_t *gpGlobals; - -#ifdef _MSC_VER -#pragma warning( disable : 4244 ) -#endif - - -int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - mins[0] = pseqdesc[ sequence ].bbmin[0]; - mins[1] = pseqdesc[ sequence ].bbmin[1]; - mins[2] = pseqdesc[ sequence ].bbmin[2]; - - maxs[0] = pseqdesc[ sequence ].bbmax[0]; - maxs[1] = pseqdesc[ sequence ].bbmax[1]; - maxs[2] = pseqdesc[ sequence ].bbmax[2]; - - return 1; -} - - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weighttotal = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - weighttotal += pseqdesc[i].actweight; - if (!weighttotal || RANDOM_LONG(0,weighttotal-1) < pseqdesc[i].actweight) - seq = i; - } - } - - return seq; -} - - -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr ) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - int weight = 0; - int seq = ACTIVITY_NOT_AVAILABLE; - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].activity == activity) - { - if ( pseqdesc[i].actweight > weight ) - { - weight = pseqdesc[i].actweight; - seq = i; - } - } - } - - return seq; -} - -void GetEyePosition ( void *pmodel, float *vecEyePosition ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - - if ( !pstudiohdr ) - { - ALERT ( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" ); - return; - } - - VectorCopy ( pstudiohdr->eyeposition, vecEyePosition ); -} - -int LookupSequence( void *pmodel, const char *label ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - for (int i = 0; i < pstudiohdr->numseq; i++) - { - if (stricmp( pseqdesc[i].label, label ) == 0) - return i; - } - - return -1; -} - - -int IsSoundEvent( int eventNumber ) -{ - if ( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE ) - return 1; - return 0; -} - - -void SequencePrecache( void *pmodel, const char *pSequenceName ) -{ - int index = LookupSequence( pmodel, pSequenceName ); - if ( index >= 0 ) - { - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || index >= pstudiohdr->numseq ) - return; - - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + index; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - for (int i = 0; i < pseqdesc->numevents; i++) - { - // Don't send client-side events to the server AI - if ( pevent[i].event >= EVENT_CLIENT ) - continue; - - // UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy - // of it's name if it is. - if ( IsSoundEvent( pevent[i].event ) ) - { - if ( !strlen(pevent[i].options) ) - { - ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options ); - } - - PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) ); - } - } - } -} - - - -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - mstudioseqdesc_t *pseqdesc; - - if (pev->sequence >= pstudiohdr->numseq) - { - *pflFrameRate = 0.0; - *pflGroundSpeed = 0.0; - return; - } - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->numframes > 1) - { - *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); - *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); - *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); - } - else - { - *pflFrameRate = 256.0; - *pflGroundSpeed = 0.0; - } -} - - -int GetSequenceFlags( void *pmodel, entvars_t *pev ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) - return 0; - - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - return pseqdesc->flags; -} - - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent ) - return 0; - - mstudioseqdesc_t *pseqdesc; - mstudioevent_t *pevent; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - pevent = (mstudioevent_t *)((byte *)pstudiohdr + pseqdesc->eventindex); - - if (pseqdesc->numevents == 0 || index > pseqdesc->numevents ) - return 0; - - if (pseqdesc->numframes > 1) - { - flStart *= (pseqdesc->numframes - 1) / 256.0; - flEnd *= (pseqdesc->numframes - 1) / 256.0; - } - else - { - flStart = 0; - flEnd = 1.0; - } - - for (; index < pseqdesc->numevents; index++) - { - // Don't send client-side events to the server AI - if ( pevent[index].event >= EVENT_CLIENT ) - continue; - - if ( (pevent[index].frame >= flStart && pevent[index].frame < flEnd) || - ((pseqdesc->flags & STUDIO_LOOPING) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1) ) - { - pMonsterEvent->event = pevent[index].event; - pMonsterEvent->options = pevent[index].options; - return index + 1; - } - } - return 0; -} - -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ) -{ - studiohdr_t *pstudiohdr; - int i; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); - - // find first controller that matches the index - for (i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++) - { - if (pbonecontroller->index == iController) - break; - } - if (i >= pstudiohdr->numbonecontrollers) - return flValue; - - // wrap 0..360 if it's a rotational controller - - if (pbonecontroller->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pbonecontroller->end < pbonecontroller->start) - flValue = -flValue; - - // does the controller not wrap? - if (pbonecontroller->start + 359.0 >= pbonecontroller->end) - { - if (flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0) - 180) - flValue = flValue + 360; - } - else - { - if (flValue > 360) - flValue = flValue - (int)(flValue / 360.0) * 360.0; - else if (flValue < 0) - flValue = flValue + (int)((flValue / -360.0) + 1) * 360.0; - } - } - - int setting = static_cast(255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start)); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - pev->controller[iController] = setting; - - return setting * (1.0 / 255.0) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; -} - - -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return flValue; - - mstudioseqdesc_t *pseqdesc; - - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; - - if (pseqdesc->blendtype[iBlender] == 0) - return flValue; - - if (pseqdesc->blendtype[iBlender] & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if (pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender]) - flValue = -flValue; - - // does the controller not wrap? - if (pseqdesc->blendstart[iBlender] + 359.0 >= pseqdesc->blendend[iBlender]) - { - if (flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) + 180) - flValue = flValue - 360; - if (flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0) - 180) - flValue = flValue + 360; - } - } - - int setting = static_cast(255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender])); - - if (setting < 0) setting = 0; - if (setting > 255) setting = 255; - - pev->blending[iBlender] = setting; - - return setting * (1.0 / 255.0) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender]; -} - - - - -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return iGoalAnim; - - mstudioseqdesc_t *pseqdesc; - pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - - // bail if we're going to or from a node 0 - if (pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0) - { - return iGoalAnim; - } - - int iEndNode; - - // ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode ); - - if (*piDir > 0) - { - iEndNode = pseqdesc[iEndingAnim].exitnode; - } - else - { - iEndNode = pseqdesc[iEndingAnim].entrynode; - } - - if (iEndNode == pseqdesc[iGoalAnim].entrynode) - { - *piDir = 1; - return iGoalAnim; - } - - byte *pTransition = ((byte *)pstudiohdr + pstudiohdr->transitionindex); - - int iInternNode = pTransition[(iEndNode-1)*pstudiohdr->numtransitions + (pseqdesc[iGoalAnim].entrynode-1)]; - - if (iInternNode == 0) - return iGoalAnim; - - int i; - - // look for someone going - for (i = 0; i < pstudiohdr->numseq; i++) - { - if (pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode) - { - *piDir = 1; - return i; - } - if (pseqdesc[i].nodeflags) - { - if (pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode) - { - *piDir = -1; - return i; - } - } - } - - ALERT( at_console, "error in transition graph" ); - return iGoalAnim; -} - -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return; - - if (iGroup > pstudiohdr->numbodyparts) - return; - - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (iValue >= pbodypart->nummodels) - return; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - pev->body = (pev->body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base)); -} - - -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ) -{ - studiohdr_t *pstudiohdr; - - pstudiohdr = (studiohdr_t *)pmodel; - if (! pstudiohdr) - return 0; - - if (iGroup > pstudiohdr->numbodyparts) - return 0; - - mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + iGroup; - - if (pbodypart->nummodels <= 1) - return 0; - - int iCurrent = (pev->body / pbodypart->base) % pbodypart->nummodels; - - return iCurrent; -} diff --git a/sdk/dlls/animation.h b/sdk/dlls/animation.h deleted file mode 100644 index 174bd71..0000000 --- a/sdk/dlls/animation.h +++ /dev/null @@ -1,47 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ANIMATION_H -#define ANIMATION_H - -#define ACTIVITY_NOT_AVAILABLE -1 - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -extern int IsSoundEvent( int eventNumber ); - -int LookupActivity( void *pmodel, entvars_t *pev, int activity ); -int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ); -int LookupSequence( void *pmodel, const char *label ); -void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ); -int GetSequenceFlags( void *pmodel, entvars_t *pev ); -int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); -float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); -float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); -void GetEyePosition( void *pmodel, float *vecEyePosition ); -void SequencePrecache( void *pmodel, const char *pSequenceName ); -int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); -void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); -int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); - -int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); -int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); - -// From /engine/studio.h -#define STUDIO_LOOPING 0x0001 - - -#endif //ANIMATION_H diff --git a/sdk/dlls/apache.cpp b/sdk/dlls/apache.cpp deleted file mode 100644 index d26015f..0000000 --- a/sdk/dlls/apache.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SF_WAITFORTRIGGER (0x04 | 0x40) // UNDONE: Fix! -#define SF_NOWRECKAGE 0x08 - -class CApache : public CBaseMonster -{ - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_HUMAN_MILITARY; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -300, -300, -172); - pev->absmax = pev->origin + Vector(300, 300, 8); - } - - void EXPORT HuntThink( void ); - void EXPORT FlyTouch( CBaseEntity *pOther ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - - void ShowDamage( void ); - void Flight( void ); - void FireRocket( void ); - BOOL FireGun( void ); - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - int m_iRockets; - float m_flForce; - float m_flNextRocket; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - Vector m_vecGoal; - - Vector m_angGun; - float m_flLastSeen; - float m_flPrevSeen; - - int m_iSoundState; // don't save this - - int m_iSpriteTexture; - int m_iExplode; - int m_iBodyGibs; - - float m_flGoalSpeed; - - int m_iDoSmokePuff; - CBeam *m_pBeam; -}; -LINK_ENTITY_TO_CLASS( monster_apache, CApache ); - -TYPEDESCRIPTION CApache::m_SaveData[] = -{ - DEFINE_FIELD( CApache, m_iRockets, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_flNextRocket, FIELD_TIME ), - DEFINE_FIELD( CApache, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CApache, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_angGun, FIELD_VECTOR ), - DEFINE_FIELD( CApache, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CApache, m_flPrevSeen, FIELD_TIME ), -// DEFINE_FIELD( CApache, m_iSoundState, FIELD_INTEGER ), // Don't save, precached -// DEFINE_FIELD( CApache, m_iSpriteTexture, FIELD_INTEGER ), -// DEFINE_FIELD( CApache, m_iExplode, FIELD_INTEGER ), -// DEFINE_FIELD( CApache, m_iBodyGibs, FIELD_INTEGER ), - DEFINE_FIELD( CApache, m_pBeam, FIELD_CLASSPTR ), - DEFINE_FIELD( CApache, m_flGoalSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CApache, m_iDoSmokePuff, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CApache, CBaseMonster ); - - -void CApache :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/apache.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -64 ), Vector( 32, 32, 0 ) ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.apacheHealth; - - m_flFieldOfView = -0.707; // 270 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0, 0xFF); - - InitBoneControllers(); - - if (pev->spawnflags & SF_WAITFORTRIGGER) - { - SetUse( &CApache::StartupUse ); - } - else - { - SetThink( &CApache::HuntThink ); - SetTouch( &CApache::FlyTouch ); - pev->nextthink = gpGlobals->time + 1.0; - } - - m_iRockets = 10; -} - - -void CApache::Precache( void ) -{ - PRECACHE_MODEL("models/apache.mdl"); - - PRECACHE_SOUND("apache/ap_rotor1.wav"); - PRECACHE_SOUND("apache/ap_rotor2.wav"); - PRECACHE_SOUND("apache/ap_rotor3.wav"); - PRECACHE_SOUND("apache/ap_whine1.wav"); - - PRECACHE_SOUND("weapons/mortarhit.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/white.spr" ); - - PRECACHE_SOUND("turret/tu_fire1.wav"); - - PRECACHE_MODEL("sprites/lgtning.spr"); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" ); - - UTIL_PrecacheOther( "hvr_rocket" ); -} - - - -void CApache::NullThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CApache::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CApache::HuntThink ); - SetTouch( &CApache::FlyTouch ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( NULL ); -} - -void CApache :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( &CApache::DyingThink ); - SetTouch( &CApache::CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - if (pev->spawnflags & SF_NOWRECKAGE) - { - m_flNextRocket = gpGlobals->time + 4.0; - } - else - { - m_flNextRocket = gpGlobals->time + 15.0; - } -} - -void CApache :: DyingThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if (m_flNextRocket > gpGlobals->time ) - { - // random explosions - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( pev->origin.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 100 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( 400 ); - WRITE_COORD( 400 ); - WRITE_COORD( 132 ); - - // velocity - WRITE_COORD( pev->velocity.x ); - WRITE_COORD( pev->velocity.y ); - WRITE_COORD( pev->velocity.z ); - - // randomization - WRITE_BYTE( 50 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 4 ); // let client decide - - // duration - WRITE_BYTE( 30 );// 3.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - // don't stop it we touch a entity - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.2; - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 300 ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate - MESSAGE_END(); - */ - - // fireball - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 256 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 120 ); // scale * 10 - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); - - // big smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 5 ); // framerate - MESSAGE_END(); - - // blast circle - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 4 ); // life - WRITE_BYTE( 32 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 192 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); - - RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); - - if (/*!(pev->spawnflags & SF_NOWRECKAGE) && */(pev->flags & FL_ONGROUND)) - { - CBaseEntity *pWreckage = Create( "cycler_wreckage", pev->origin, pev->angles ); - // SET_MODEL( ENT(pWreckage->pev), STRING(pev->model) ); - UTIL_SetSize( pWreckage->pev, Vector( -200, -200, -128 ), Vector( 200, 200, -32 ) ); - pWreckage->pev->frame = pev->frame; - pWreckage->pev->sequence = pev->sequence; - pWreckage->pev->framerate = 0; - pWreckage->pev->dmgtime = gpGlobals->time + 5; - } - - // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 64); - - // size - WRITE_COORD( 400 ); - WRITE_COORD( 400 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 200 ); - - // randomization - WRITE_BYTE( 30 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 200 ); - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - SetThink( &CApache::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - - -void CApache::FlyTouch( CBaseEntity *pOther ) -{ - // bounce if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - - // UNDONE, do a real bounce - pev->velocity = pev->velocity + tr.vecPlaneNormal * (pev->velocity.Length() + 200); - } -} - - -void CApache::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( NULL ); - m_flNextRocket = gpGlobals->time; - pev->nextthink = gpGlobals->time; - } -} - - - -void CApache :: GibMonster( void ) -{ - // EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - -void CApache :: HuntThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - ShowDamage( ); - - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ) ); - if (m_pGoalEnt) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - } - } - - // if (m_hEnemy == NULL) - { - Look( 4092 ); - m_hEnemy = BestVisibleEnemy( ); - } - - // generic speed up - if (m_flGoalSpeed < 800) - m_flGoalSpeed += 5; - - if (m_hEnemy != 0) - { - // ALERT( at_console, "%s\n", STRING( m_hEnemy->pev->classname ) ); - if (FVisible( m_hEnemy )) - { - if (m_flLastSeen < gpGlobals->time - 5) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->Center( ); - } - else - { - m_hEnemy = NULL; - } - } - - m_vecTarget = (m_posTarget - pev->origin).Normalize(); - - float flLength = (pev->origin - m_posDesired).Length(); - - if (m_pGoalEnt) - { - // ALERT( at_console, "%.0f\n", flLength ); - - if (flLength < 128) - { - m_pGoalEnt = UTIL_FindEntityByTargetname( NULL, STRING( m_pGoalEnt->pev->target ) ); - if (m_pGoalEnt) - { - m_posDesired = m_pGoalEnt->pev->origin; - UTIL_MakeAimVectors( m_pGoalEnt->pev->angles ); - m_vecGoal = gpGlobals->v_forward; - flLength = (pev->origin - m_posDesired).Length(); - } - } - } - else - { - m_posDesired = pev->origin; - } - - if (flLength > 250) // 500 - { - // float flLength2 = (m_posTarget - pev->origin).Length() * (1.5 - DotProduct((m_posTarget - pev->origin).Normalize(), pev->velocity.Normalize() )); - // if (flLength2 < flLength) - if (m_flLastSeen + 90 > gpGlobals->time && DotProduct( (m_posTarget - pev->origin).Normalize(), (m_posDesired - pev->origin).Normalize( )) > 0.25) - { - m_vecDesired = (m_posTarget - pev->origin).Normalize( ); - } - else - { - m_vecDesired = (m_posDesired - pev->origin).Normalize( ); - } - } - else - { - m_vecDesired = m_vecGoal; - } - - Flight( ); - - // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->time, m_flLastSeen, m_flPrevSeen ); - if ((m_flLastSeen + 1 > gpGlobals->time) && (m_flPrevSeen + 2 < gpGlobals->time)) - { - if (FireGun( )) - { - // slow down if we're fireing - if (m_flGoalSpeed > 400) - m_flGoalSpeed = 400; - } - - // don't fire rockets and gun on easy mode - if (g_iSkillLevel == SKILL_EASY) - m_flNextRocket = gpGlobals->time + 10.0; - } - - UTIL_MakeAimVectors( pev->angles ); - Vector vecEst = (gpGlobals->v_forward * 800 + pev->velocity).Normalize( ); - // ALERT( at_console, "%d %d %d %4.2f\n", pev->angles.x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->time, DotProduct( m_vecTarget, vecEst ) ); - - if ((m_iRockets % 2) == 1) - { - FireRocket( ); - m_flNextRocket = gpGlobals->time + 0.5; - if (m_iRockets <= 0) - { - m_flNextRocket = gpGlobals->time + 10; - m_iRockets = 10; - } - } - else if (pev->angles.x < 0 && DotProduct( pev->velocity, gpGlobals->v_forward ) > -100 && m_flNextRocket < gpGlobals->time) - { - if (m_flLastSeen + 60 > gpGlobals->time) - { - if (m_hEnemy != 0) - { - // make sure it's a good shot - if (DotProduct( m_vecTarget, vecEst) > .965) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, ignore_monsters, edict(), &tr ); - if ((tr.vecEndPos - m_posTarget).Length() < 512) - FireRocket( ); - } - } - else - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, pev->origin + vecEst * 4096, dont_ignore_monsters, edict(), &tr ); - // just fire when close - if ((tr.vecEndPos - m_posTarget).Length() < 512) - FireRocket( ); - } - } - } -} - - -void CApache :: Flight( void ) -{ - // tilt model 5 degrees - Vector vecAdj = Vector( 5.0, 0, 0 ); - - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 2 + vecAdj); - // Vector vecEst1 = pev->origin + pev->velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if (flSide < 0) - { - if (pev->avelocity.y < 60) - { - pev->avelocity.y += 8; // 9 * (3.0/2.0); - } - } - else - { - if (pev->avelocity.y > -60) - { - pev->avelocity.y -= 8; // 9 * (3.0/2.0); - } - } - pev->avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - UTIL_MakeAimVectors( pev->angles + pev->avelocity * 1 + vecAdj); - Vector vecEst = pev->origin + pev->velocity * 2.0 + gpGlobals->v_up * m_flForce * 20 - Vector( 0, 0, 384 * 2 ); - - // add immediate force - UTIL_MakeAimVectors( pev->angles + vecAdj); - pev->velocity.x += gpGlobals->v_up.x * m_flForce; - pev->velocity.y += gpGlobals->v_up.y * m_flForce; - pev->velocity.z += gpGlobals->v_up.z * m_flForce; - // add gravity - pev->velocity.z -= 38.4; // 32ft/sec - - - float flSpeed = pev->velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( pev->velocity.x, pev->velocity.y, 0 ) ); - if (flDir < 0) - flSpeed = -flSpeed; - - float flDist = DotProduct( m_posDesired - vecEst, gpGlobals->v_forward ); - - // float flSlip = DotProduct( pev->velocity, gpGlobals->v_right ); - float flSlip = -DotProduct( m_posDesired - vecEst, gpGlobals->v_right ); - - // fly sideways - if (flSlip > 0) - { - if (pev->angles.z > -30 && pev->avelocity.z > -15) - pev->avelocity.z -= 4; - else - pev->avelocity.z += 2; - } - else - { - - if (pev->angles.z < 30 && pev->avelocity.z < 15) - pev->avelocity.z += 4; - else - pev->avelocity.z -= 2; - } - - // sideways drag - pev->velocity.x = pev->velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); - pev->velocity.y = pev->velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); - pev->velocity.z = pev->velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); - - // general drag - pev->velocity = pev->velocity * 0.995; - - // apply power to stay correct height - if (m_flForce < 80 && vecEst.z < m_posDesired.z) - { - m_flForce += 12; - } - else if (m_flForce > 30) - { - if (vecEst.z > m_posDesired.z) - m_flForce -= 8; - } - - // pitch forward or back to get to target - if (flDist > 0 && flSpeed < m_flGoalSpeed /* && flSpeed < flDist */ && pev->angles.x + pev->avelocity.x > -40) - { - // ALERT( at_console, "F " ); - // lean forward - pev->avelocity.x -= 12.0; - } - else if (flDist < 0 && flSpeed > -50 && pev->angles.x + pev->avelocity.x < 20) - { - // ALERT( at_console, "B " ); - // lean backward - pev->avelocity.x += 12.0; - } - else if (pev->angles.x + pev->avelocity.x > 0) - { - // ALERT( at_console, "f " ); - pev->avelocity.x -= 4.0; - } - else if (pev->angles.x + pev->avelocity.x < 0) - { - // ALERT( at_console, "b " ); - pev->avelocity.x += 4.0; - } - - // ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", pev->origin.x, pev->velocity.x, flDist, flSpeed, pev->angles.x, pev->avelocity.x, m_flForce ); - // ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", pev->origin.z, pev->velocity.z, vecEst.z, m_posDesired.z, m_flForce ); - - // make rotor, engine sounds - if (m_iSoundState == 0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, 0, 110 ); - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) - { - - float pitch = DotProduct( pev->velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); - - pitch = (int)(100 + pitch / 50.0); - - if (pitch > 250) - pitch = 250; - if (pitch < 50) - pitch = 50; - if (pitch == 100) - pitch = 101; - - float flVol = (m_flForce / 100.0) + .1; - if (flVol > 1.0) - flVol = 1.0; - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor2.wav", 1.0, 0.3, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - } - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - - // ALERT( at_console, "%.0f %.2f\n", pitch, flVol ); - } -} - - -void CApache :: FireRocket( void ) -{ - static float side = 1.0; - - if (m_iRockets <= 0) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + 1.5 * (gpGlobals->v_forward * 21 + gpGlobals->v_right * 70 * side + gpGlobals->v_up * -79); - - switch( m_iRockets % 5) - { - case 0: vecSrc = vecSrc + gpGlobals->v_right * 10; break; - case 1: vecSrc = vecSrc - gpGlobals->v_right * 10; break; - case 2: vecSrc = vecSrc + gpGlobals->v_up * 10; break; - case 3: vecSrc = vecSrc - gpGlobals->v_up * 10; break; - case 4: break; - } - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - - CBaseEntity *pRocket = CBaseEntity::Create( "hvr_rocket", vecSrc, pev->angles, edict() ); - if (pRocket) - pRocket->pev->velocity = pev->velocity + gpGlobals->v_forward * 100; - - m_iRockets--; - - side = - side; -} - - - -BOOL CApache :: FireGun( ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector posGun, angGun; - GetAttachment( 1, posGun, angGun ); - - Vector vecTarget = (m_posTarget - posGun).Normalize( ); - - Vector vecOut; - - vecOut.x = DotProduct( gpGlobals->v_forward, vecTarget ); - vecOut.y = -DotProduct( gpGlobals->v_right, vecTarget ); - vecOut.z = DotProduct( gpGlobals->v_up, vecTarget ); - - Vector angles = UTIL_VecToAngles (vecOut); - - angles.x = -angles.x; - if (angles.y > 180) - angles.y = angles.y - 360; - if (angles.y < -180) - angles.y = angles.y + 360; - if (angles.x > 180) - angles.x = angles.x - 360; - if (angles.x < -180) - angles.x = angles.x + 360; - - if (angles.x > m_angGun.x) - m_angGun.x = min( angles.x, m_angGun.x + 12 ); - if (angles.x < m_angGun.x) - m_angGun.x = max( angles.x, m_angGun.x - 12 ); - if (angles.y > m_angGun.y) - m_angGun.y = min( angles.y, m_angGun.y + 12 ); - if (angles.y < m_angGun.y) - m_angGun.y = max( angles.y, m_angGun.y - 12 ); - - m_angGun.y = SetBoneController( 0, m_angGun.y ); - m_angGun.x = SetBoneController( 1, m_angGun.x ); - - Vector posBarrel, angBarrel; - GetAttachment( 0, posBarrel, angBarrel ); - Vector vecGun = (posBarrel - posGun).Normalize( ); - - if (DotProduct( vecGun, vecTarget ) > 0.98) - { -#if 1 - FireBullets( 1, posGun, vecGun, VECTOR_CONE_4DEGREES, 8192, BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.3); -#else - static float flNext; - TraceResult tr; - UTIL_TraceLine( posGun, posGun + vecGun * 8192, dont_ignore_monsters, ENT( pev ), &tr ); - - if (!m_pBeam) - { - m_pBeam = CBeam::BeamCreate( "sprites/lgtning.spr", 80 ); - m_pBeam->PointEntInit( pev->origin, entindex( ) ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } - - if (flNext < gpGlobals->time) - { - flNext = gpGlobals->time + 0.5; - m_pBeam->SetStartPos( tr.vecEndPos ); - } -#endif - return TRUE; - } - else - { - if (m_pBeam) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - } - return FALSE; -} - - - -void CApache :: ShowDamage( void ) -{ - if (m_iDoSmokePuff > 0 || RANDOM_LONG(0,99) > pev->health) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - if (m_iDoSmokePuff > 0) - m_iDoSmokePuff--; -} - - -int CApache :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (pevInflictor->owner == edict()) - return 0; - - if (bitsDamageType & DMG_BLAST) - { - flDamage *= 2; - } - - /* - if ( (bitsDamageType & DMG_BULLET) && flDamage > 50) - { - // clip bullet damage at 50 - flDamage = 50; - } - */ - - // ALERT( at_console, "%.0f\n", flDamage ); - return CBaseEntity::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - - -void CApache::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // ignore blades - if (ptr->iHitgroup == 6 && (bitsDamageType & (DMG_ENERGYBEAM|DMG_BULLET|DMG_CLUB))) - return; - - // hit hard, hits cockpit, hits engines - if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - m_iDoSmokePuff = 3 + (flDamage / 5.0); - } - else - { - // do half damage in the body - // AddMultiDamage( pevAttacker, this, flDamage / 2.0, bitsDamageType ); - UTIL_Ricochet( ptr->vecEndPos, 2.0 ); - } -} - - - - - -class CApacheHVR : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void EXPORT IgniteThink( void ); - void EXPORT AccelerateThink( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iTrail; - Vector m_vecForward; -}; -LINK_ENTITY_TO_CLASS( hvr_rocket, CApacheHVR ); - -TYPEDESCRIPTION CApacheHVR::m_SaveData[] = -{ -// DEFINE_FIELD( CApacheHVR, m_iTrail, FIELD_INTEGER ), // Dont' save, precache - DEFINE_FIELD( CApacheHVR, m_vecForward, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CApacheHVR, CGrenade ); - -void CApacheHVR :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/HVR.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CApacheHVR::IgniteThink ); - SetTouch( &CApacheHVR::ExplodeTouch ); - - UTIL_MakeAimVectors( pev->angles ); - m_vecForward = gpGlobals->v_forward; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.1; - - pev->dmg = 150; -} - - -void CApacheHVR :: Precache( void ) -{ - PRECACHE_MODEL("models/HVR.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); -} - - -void CApacheHVR :: IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - // pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(m_iTrail ); // model - WRITE_BYTE( 15 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - // set to accelerate - SetThink( &CApacheHVR::AccelerateThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CApacheHVR :: AccelerateThink( void ) -{ - // check world boundaries - if (pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - UTIL_Remove( this ); - return; - } - - // accelerate - float flSpeed = pev->velocity.Length(); - if (flSpeed < 1800) - { - pev->velocity = pev->velocity + m_vecForward * 200; - } - - // re-aim - pev->angles = UTIL_VecToAngles( pev->velocity ); - - pev->nextthink = gpGlobals->time + 0.1; -} - - -#endif diff --git a/sdk/dlls/barnacle.cpp b/sdk/dlls/barnacle.cpp deleted file mode 100644 index 3697b5b..0000000 --- a/sdk/dlls/barnacle.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// barnacle - stationary ceiling mounted 'fishing' monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is. -#define BARNACLE_PULL_SPEED 8 -#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them. - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BARNACLE_AE_PUKEGIB 2 - -class CBarnacle : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - CBaseEntity *TongueTouchEnt ( float *pflLength ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void EXPORT BarnacleThink ( void ); - void EXPORT WaitTillDead ( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flAltitude; - float m_flKillVictimTime; - int m_cGibs;// barnacle loads up on gibs each time it kills something. - BOOL m_fTongueExtended; - BOOL m_fLiftingPrey; - float m_flTongueAdj; -}; -LINK_ENTITY_TO_CLASS( monster_barnacle, CBarnacle ); - -TYPEDESCRIPTION CBarnacle::m_SaveData[] = -{ - DEFINE_FIELD( CBarnacle, m_flAltitude, FIELD_FLOAT ), - DEFINE_FIELD( CBarnacle, m_flKillVictimTime, FIELD_TIME ), - DEFINE_FIELD( CBarnacle, m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something. - DEFINE_FIELD( CBarnacle, m_fTongueExtended, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_fLiftingPrey, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarnacle, m_flTongueAdj, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarnacle, CBaseMonster ); - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarnacle :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarnacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNACLE_AE_PUKEGIB: - CGib::SpawnRandomGibs( pev, 1, 1 ); - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarnacle :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/barnacle.mdl"); - UTIL_SetSize( pev, Vector(-16, -16, -32), Vector(16, 16, 0) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_AIM; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = EF_INVLIGHT; // take light from the ceiling - pev->health = 25; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flKillVictimTime = 0; - m_cGibs = 0; - m_fLiftingPrey = FALSE; - m_flTongueAdj = -100; - - InitBoneControllers(); - - SetActivity ( ACT_IDLE ); - - SetThink ( &CBarnacle::BarnacleThink ); - pev->nextthink = gpGlobals->time + 0.5; - - UTIL_SetOrigin ( pev, pev->origin ); -} - -int CBarnacle::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( bitsDamageType & DMG_CLUB ) - { - flDamage = pev->health; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CBarnacle :: BarnacleThink ( void ) -{ - CBaseEntity *pTouchEnt; - CBaseMonster *pVictim; - float flLength; - - pev->nextthink = gpGlobals->time + 0.1; - - if ( m_hEnemy != 0 ) - { -// barnacle has prey. - - if ( !m_hEnemy->IsAlive() ) - { - // someone (maybe even the barnacle) killed the prey. Reset barnacle. - m_fLiftingPrey = FALSE;// indicate that we're not lifting prey. - m_hEnemy = NULL; - return; - } - - if ( m_fLiftingPrey ) - { - if ( m_hEnemy != 0 && m_hEnemy->pev->deadflag != DEAD_NO ) - { - // crap, someone killed the prey on the way up. - m_hEnemy = NULL; - m_fLiftingPrey = FALSE; - return; - } - - // still pulling prey. - Vector vecNewEnemyOrigin = m_hEnemy->pev->origin; - vecNewEnemyOrigin.x = pev->origin.x; - vecNewEnemyOrigin.y = pev->origin.y; - - // guess as to where their neck is - vecNewEnemyOrigin.x -= 6 * cos(m_hEnemy->pev->angles.y * M_PI/180.0); - vecNewEnemyOrigin.y -= 6 * sin(m_hEnemy->pev->angles.y * M_PI/180.0); - - m_flAltitude -= BARNACLE_PULL_SPEED; - vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED; - - if ( fabs( pev->origin.z - ( vecNewEnemyOrigin.z + m_hEnemy->pev->view_ofs.z - 8 ) ) < BARNACLE_BODY_HEIGHT ) - { - // prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body ) - m_fLiftingPrey = FALSE; - - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_bite3.wav", 1, ATTN_NORM ); - - pVictim = m_hEnemy->MyMonsterPointer(); - - m_flKillVictimTime = gpGlobals->time + 10;// now that the victim is in place, the killing bite will be administered in 10 seconds. - - if ( pVictim ) - { - pVictim->BarnacleVictimBitten( pev ); - SetActivity ( ACT_EAT ); - } - } - - UTIL_SetOrigin ( m_hEnemy->pev, vecNewEnemyOrigin ); - } - else - { - // prey is lifted fully into feeding position and is dangling there. - - pVictim = m_hEnemy->MyMonsterPointer(); - - if ( m_flKillVictimTime != -1 && gpGlobals->time > m_flKillVictimTime ) - { - // kill! - if ( pVictim ) - { - pVictim->TakeDamage ( pev, pev, pVictim->pev->health, DMG_SLASH | DMG_ALWAYSGIB ); - m_cGibs = 3; - } - - return; - } - - // bite prey every once in a while - if ( pVictim && ( RANDOM_LONG(0,49) == 0 ) ) - { - switch ( RANDOM_LONG(0,2) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; - } - - pVictim->BarnacleVictimBitten( pev ); - } - - } - } - else - { -// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue. - - // If idle and no nearby client, don't think so often - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); // Stagger a bit to keep barnacles from thinking on the same frame - - if ( m_fSequenceFinished ) - {// this is done so barnacle will fidget. - SetActivity ( ACT_IDLE ); - m_flTongueAdj = -100; - } - - if ( m_cGibs && RANDOM_LONG(0,99) == 1 ) - { - // cough up a gib. - CGib::SpawnRandomGibs( pev, 1, 1 ); - m_cGibs--; - - switch ( RANDOM_LONG(0,2) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew2.wav", 1, ATTN_NORM ); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_chew3.wav", 1, ATTN_NORM ); break; - } - } - - pTouchEnt = TongueTouchEnt( &flLength ); - - if ( pTouchEnt != NULL && m_fTongueExtended ) - { - // tongue is fully extended, and is touching someone. - if ( pTouchEnt->FBecomeProne() ) - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_alert2.wav", 1, ATTN_NORM ); - - SetSequenceByName ( "attack1" ); - m_flTongueAdj = -20; - - m_hEnemy = pTouchEnt; - - pTouchEnt->pev->movetype = MOVETYPE_FLY; - pTouchEnt->pev->velocity = g_vecZero; - pTouchEnt->pev->basevelocity = g_vecZero; - pTouchEnt->pev->origin.x = pev->origin.x; - pTouchEnt->pev->origin.y = pev->origin.y; - - m_fLiftingPrey = TRUE;// indicate that we should be lifting prey. - m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted. - - m_flAltitude = (pev->origin.z - pTouchEnt->EyePosition().z); - } - } - else - { - // calculate a new length for the tongue to be clear of anything else that moves under it. - if ( m_flAltitude < flLength ) - { - // if tongue is higher than is should be, lower it kind of slowly. - m_flAltitude += BARNACLE_PULL_SPEED; - m_fTongueExtended = FALSE; - } - else - { - m_flAltitude = flLength; - m_fTongueExtended = TRUE; - } - - } - - } - - // ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj ); - SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) ); - StudioFrameAdvance( 0.1 ); -} - -//========================================================= -// Killed. -//========================================================= -void CBarnacle :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster *pVictim; - - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - - if ( m_hEnemy != 0 ) - { - pVictim = m_hEnemy->MyMonsterPointer(); - - if ( pVictim ) - { - pVictim->BarnacleVictimReleased(); - } - } - -// CGib::SpawnRandomGibs( pev, 4, 1 ); - - switch ( RANDOM_LONG ( 0, 1 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die1.wav", 1, ATTN_NORM ); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_WEAPON, "barnacle/bcl_die3.wav", 1, ATTN_NORM ); break; - } - - SetActivity ( ACT_DIESIMPLE ); - SetBoneController( 0, 0 ); - - StudioFrameAdvance( 0.1 ); - - pev->nextthink = gpGlobals->time + 0.1; - SetThink ( &CBarnacle::WaitTillDead ); -} - -//========================================================= -//========================================================= -void CBarnacle :: WaitTillDead ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - float flInterval = StudioFrameAdvance( 0.1 ); - DispatchAnimEvents ( flInterval ); - - if ( m_fSequenceFinished ) - { - // death anim finished. - StopAnimation(); - SetThink ( NULL ); - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarnacle :: Precache() -{ - PRECACHE_MODEL("models/barnacle.mdl"); - - PRECACHE_SOUND("barnacle/bcl_alert2.wav");//happy, lifting food up - PRECACHE_SOUND("barnacle/bcl_bite3.wav");//just got food to mouth - PRECACHE_SOUND("barnacle/bcl_chew1.wav"); - PRECACHE_SOUND("barnacle/bcl_chew2.wav"); - PRECACHE_SOUND("barnacle/bcl_chew3.wav"); - PRECACHE_SOUND("barnacle/bcl_die1.wav" ); - PRECACHE_SOUND("barnacle/bcl_die3.wav" ); -} - -//========================================================= -// TongueTouchEnt - does a trace along the barnacle's tongue -// to see if any entity is touching it. Also stores the length -// of the trace in the int pointer provided. -//========================================================= -#define BARNACLE_CHECK_SPACING 8 -CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength ) -{ - TraceResult tr; - float length; - - // trace once to hit architecture and see if the tongue needs to change position. - UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0 , 0 , 2048 ), ignore_monsters, ENT(pev), &tr ); - length = fabs( pev->origin.z - tr.vecEndPos.z ); - if ( pflLength ) - { - *pflLength = length; - } - - Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 ); - Vector mins = pev->origin - delta; - Vector maxs = pev->origin + delta; - maxs.z = pev->origin.z; - mins.z -= length; - - CBaseEntity *pList[10]; - int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - // only clients and monsters - if ( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it. - { - return pList[i]; - } - } - } - - return NULL; -} diff --git a/sdk/dlls/barney.cpp b/sdk/dlls/barney.cpp deleted file mode 100644 index 2a9f1b4..0000000 --- a/sdk/dlls/barney.cpp +++ /dev/null @@ -1,843 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -// UNDONE: Holster weapon? - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "weapons.h" -#include "soundent.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -// first flag is barney dying for scripted sequences? -#define BARNEY_AE_DRAW ( 2 ) -#define BARNEY_AE_SHOOT ( 3 ) -#define BARNEY_AE_HOLSTER ( 4 ) - -#define BARNEY_BODY_GUNHOLSTERED 0 -#define BARNEY_BODY_GUNDRAWN 1 -#define BARNEY_BODY_GUNGONE 2 - -class CBarney : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - void BarneyFirePistol( void ); - void AlertSound( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - - void DeclineFollowing( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fGunDrawn; - float m_painTime; - float m_checkAttackTime; - BOOL m_lastAttackCheck; - - // UNDONE: What is this for? It isn't used? - float m_flPlayerDamage;// how much pain has the player inflicted on me? - - CUSTOM_SCHEDULES; -}; - -LINK_ENTITY_TO_CLASS( monster_barney, CBarney ); - -TYPEDESCRIPTION CBarney::m_SaveData[] = -{ - DEFINE_FIELD( CBarney, m_fGunDrawn, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_checkAttackTime, FIELD_TIME ), - DEFINE_FIELD( CBarney, m_lastAttackCheck, FIELD_BOOLEAN ), - DEFINE_FIELD( CBarney, m_flPlayerDamage, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBarney, CTalkMonster ); - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlBaFollow[] = -{ - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slBaFollow[] = -{ - { - tlBaFollow, - ARRAYSIZE ( tlBaFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "Follow" - }, -}; - -//========================================================= -// BarneyDraw- much better looking draw schedule for when -// barney knows who he's gonna attack. -//========================================================= -Task_t tlBarneyEnemyDraw[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, 0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, -}; - -Schedule_t slBarneyEnemyDraw[] = -{ - { - tlBarneyEnemyDraw, - ARRAYSIZE ( tlBarneyEnemyDraw ), - 0, - 0, - "Barney Enemy Draw" - } -}; - -Task_t tlBaFaceTarget[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slBaFaceTarget[] = -{ - { - tlBaFaceTarget, - ARRAYSIZE ( tlBaFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - - -Task_t tlIdleBaStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleBaStand[] = -{ - { - tlIdleBaStand, - ARRAYSIZE ( tlIdleBaStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleStand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBarney ) -{ - slBaFollow, - slBarneyEnemyDraw, - slBaFaceTarget, - slIdleBaStand, -}; - - -IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster ); - -void CBarney :: StartTask( Task_t *pTask ) -{ - CTalkMonster::StartTask( pTask ); -} - -void CBarney :: RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - if (m_hEnemy != 0 && (m_hEnemy->IsPlayer())) - { - pev->framerate = 1.5; - } - CTalkMonster::RunTask( pTask ); - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - - - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CBarney :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBarney :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// ALertSound - barney says "Freeze!" -//========================================================= -void CBarney :: AlertSound( void ) -{ - if ( m_hEnemy != 0 ) - { - if ( FOkToSpeak() ) - { - PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - } - } - -} -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBarney :: SetYawSpeed ( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 70; - break; - case ACT_WALK: - ys = 70; - break; - case ACT_RUN: - ys = 90; - break; - default: - ys = 70; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBarney :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist <= 1024 && flDot >= 0.5 ) - { - if ( gpGlobals->time > m_checkAttackTime ) - { - TraceResult tr; - - Vector shootOrigin = pev->origin + Vector( 0, 0, 55 ); - CBaseEntity *pEnemy = m_hEnemy; - Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP ); - UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr ); - m_checkAttackTime = gpGlobals->time + 1; - if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) ) - m_lastAttackCheck = TRUE; - else - m_lastAttackCheck = FALSE; - m_checkAttackTime = gpGlobals->time + 1.5; - } - return m_lastAttackCheck; - } - return FALSE; -} - - -//========================================================= -// BarneyFirePistol - shoots one round from the pistol at -// the enemy barney is facing. -//========================================================= -void CBarney :: BarneyFirePistol ( void ) -{ - Vector vecShootOrigin; - - UTIL_MakeVectors(pev->angles); - vecShootOrigin = pev->origin + Vector( 0, 0, 55 ); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - pev->effects = EF_MUZZLEFLASH; - - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM ); - - int pitchShift = RANDOM_LONG( 0, 20 ); - - // Only shift about half the time - if ( pitchShift > 10 ) - pitchShift = 0; - else - pitchShift -= 5; - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift ); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - - // UNDONE: Reload? - m_cAmmoLoaded--;// take away a bullet! -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBarney :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BARNEY_AE_SHOOT: - BarneyFirePistol(); - break; - - case BARNEY_AE_DRAW: - // barney's bodygroup switches here so he can pull gun from holster - pev->body = BARNEY_BODY_GUNDRAWN; - m_fGunDrawn = TRUE; - break; - - case BARNEY_AE_HOLSTER: - // change bodygroup to replace gun in holster - pev->body = BARNEY_BODY_GUNHOLSTERED; - m_fGunDrawn = FALSE; - break; - - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBarney :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/barney.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.barneyHealth; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - - pev->body = 0; // gun in holster - m_fGunDrawn = FALSE; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - MonsterInit(); - SetUse( &CBarney::FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBarney :: Precache() -{ - PRECACHE_MODEL("models/barney.mdl"); - - PRECACHE_SOUND("barney/ba_attack1.wav" ); - PRECACHE_SOUND("barney/ba_attack2.wav" ); - - PRECACHE_SOUND("barney/ba_pain1.wav"); - PRECACHE_SOUND("barney/ba_pain2.wav"); - PRECACHE_SOUND("barney/ba_pain3.wav"); - - PRECACHE_SOUND("barney/ba_die1.wav"); - PRECACHE_SOUND("barney/ba_die2.wav"); - PRECACHE_SOUND("barney/ba_die3.wav"); - - // every new barney must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - CTalkMonster::Precache(); -} - -// Init talk data -void CBarney :: TalkInit() -{ - - CTalkMonster::TalkInit(); - - // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "BA_ANSWER"; - m_szGrp[TLK_QUESTION] = "BA_QUESTION"; - m_szGrp[TLK_IDLE] = "BA_IDLE"; - m_szGrp[TLK_STARE] = "BA_STARE"; - m_szGrp[TLK_USE] = "BA_OK"; - m_szGrp[TLK_UNUSE] = "BA_WAIT"; - m_szGrp[TLK_STOP] = "BA_STOP"; - - m_szGrp[TLK_NOSHOOT] = "BA_SCARED"; - m_szGrp[TLK_HELLO] = "BA_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!BA_CUREA"; - m_szGrp[TLK_PLHURT2] = "!BA_CUREB"; - m_szGrp[TLK_PLHURT3] = "!BA_CUREC"; - - m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE - m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE - m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE - - m_szGrp[TLK_SMELL] = "BA_SMELL"; - - m_szGrp[TLK_WOUND] = "BA_WOUND"; - m_szGrp[TLK_MORTAL] = "BA_MORTAL"; - - // get voice for head - just one barney voice for now - m_voicePitch = 100; -} - - -static BOOL IsFacing( entvars_t *pevTest, const Vector &reference ) -{ - Vector vecDir = (reference - pevTest->origin); - vecDir.z = 0; - vecDir = vecDir.Normalize(); - Vector forward, angle; - angle = pevTest->v_angle; - angle.x = 0; - UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL ); - // He's facing me, he meant it - if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so - { - return TRUE; - } - return FALSE; -} - - -int CBarney :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - // make sure friends talk about it if player hurts talkmonsters... - int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); - if ( !IsAlive() || pev->deadflag == DEAD_DYING ) - return ret; - - if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) ) - { - m_flPlayerDamage += flDamage; - - // This is a heurstic to determine if the player intended to harm me - // If I have an enemy, we can't establish intent (may just be crossfire) - if ( m_hEnemy == 0 ) - { - // If the player was facing directly at me, or I'm already suspicious, get mad - if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) ) - { - // Alright, now I'm pissed! - PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM ); - - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - else - { - // Hey, be careful with that - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - Remember( bits_MEMORY_SUSPICIOUS ); - } - } - else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) - { - PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM ); - } - } - - return ret; -} - - -//========================================================= -// PainSound -//========================================================= -void CBarney :: PainSound ( void ) -{ - if (gpGlobals->time < m_painTime) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CBarney :: DeathSound ( void ) -{ - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - - -void CBarney::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - switch( ptr->iHitgroup) - { - case HITGROUP_CHEST: - case HITGROUP_STOMACH: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST)) - { - flDamage = flDamage / 2; - } - break; - case 10: - if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB)) - { - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // always a head shot - ptr->iHitgroup = HITGROUP_HEAD; - break; - } - - CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -void CBarney::Killed( entvars_t *pevAttacker, int iGib ) -{ - if ( pev->body < BARNEY_BODY_GUNGONE ) - {// drop the gun! - Vector vecGunPos; - Vector vecGunAngles; - - pev->body = BARNEY_BODY_GUNGONE; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles ); - } - - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -Schedule_t* CBarney :: GetScheduleOfType ( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - case SCHED_ARM_WEAPON: - if ( m_hEnemy != 0 ) - { - // face enemy, then draw. - return slBarneyEnemyDraw; - } - break; - - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that barney will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slBaFaceTarget; // override this for different target face behavior - else - return psched; - - case SCHED_TARGET_CHASE: - return slBaFollow; - - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - { - // just look straight ahead. - return slIdleBaStand; - } - else - return psched; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBarney :: GetSchedule ( void ) -{ - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() ) - { - PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - // always act surprized with a new enemy - if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) ) - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - - // wait for one schedule to draw gun - if (!m_fGunDrawn ) - return GetScheduleOfType( SCHED_ARM_WEAPON ); - - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - if ( m_hEnemy == 0 && IsFollowing() ) - { - if ( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - else - { - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); - } - } - - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) - { - return GetScheduleOfType( SCHED_MOVE_AWAY ); - } - - // try to say something about smells - TrySmellTalk(); - break; - default: - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CBarney :: GetIdealState ( void ) -{ - return CTalkMonster::GetIdealState(); -} - - - -void CBarney::DeclineFollowing( void ) -{ - PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM ); -} - - - - - -//========================================================= -// DEAD BARNEY PROP -// -// Designer selects a pose in worldcraft, 0 through num_poses-1 -// this value is added to what is selected as the 'first dead pose' -// among the monster's normal animations. All dead poses must -// appear sequentially in the model file. Be sure and set -// the m_iFirstPose properly! -// -//========================================================= -class CDeadBarney : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_PLAYER_ALLY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static const char *m_szPoses[3]; -}; - -const char *CDeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; - -void CDeadBarney::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney ); - -//========================================================= -// ********** DeadBarney SPAWN ********** -//========================================================= -void CDeadBarney :: Spawn( ) -{ - PRECACHE_MODEL("models/barney.mdl"); - SET_MODEL(ENT(pev), "models/barney.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead barney with bad pose\n" ); - } - // Corpses have less health - pev->health = 8;//gSkillData.barneyHealth; - - MonsterInitDead(); -} - - diff --git a/sdk/dlls/basemonster.h b/sdk/dlls/basemonster.h deleted file mode 100644 index d0e9e9c..0000000 --- a/sdk/dlls/basemonster.h +++ /dev/null @@ -1,339 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef BASEMONSTER_H -#define BASEMONSTER_H - -// -// generic Monster -// -class CBaseMonster : public CBaseToggle -{ -private: - int m_afConditions; - -public: - typedef enum - { - SCRIPT_PLAYING = 0, // Playing the sequence - SCRIPT_WAIT, // Waiting on everyone in the script to be ready - SCRIPT_CLEANUP, // Cancelling the script / cleaning up - SCRIPT_WALK_TO_MARK, - SCRIPT_RUN_TO_MARK, - } SCRIPTSTATE; - - - - // these fields have been added in the process of reworking the state machine. (sjb) - EHANDLE m_hEnemy; // the entity that the monster is fighting. - EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach - EHANDLE m_hOldEnemy[ MAX_OLD_ENEMIES ]; - Vector m_vecOldEnemy[ MAX_OLD_ENEMIES ]; - - float m_flFieldOfView;// width of monster's field of view ( dot product ) - float m_flWaitFinished;// if we're told to wait, this is the time that the wait will be over. - float m_flMoveWaitFinished; - - Activity m_Activity;// what the monster is doing (animation) - Activity m_IdealActivity;// monster should switch to this activity - - int m_LastHitGroup; // the last body region that took damage - - MONSTERSTATE m_MonsterState;// monster's current state - MONSTERSTATE m_IdealMonsterState;// monster should change to this state - - int m_iTaskStatus; - Schedule_t *m_pSchedule; - int m_iScheduleIndex; - - WayPoint_t m_Route[ ROUTE_SIZE ]; // Positions of movement - int m_movementGoal; // Goal that defines route - int m_iRouteIndex; // index into m_Route[] - float m_moveWaitTime; // How long I should wait for something to move - - Vector m_vecMoveGoal; // kept around for node graph moves, so we know our ultimate goal - Activity m_movementActivity; // When moving, set this activity - - int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. - int m_afSoundTypes; - - Vector m_vecLastPosition;// monster sometimes wants to return to where it started after an operation. - - int m_iHintNode; // this is the hint node that the monster is moving towards or performing active idle on. - - int m_afMemory; - - int m_iMaxHealth;// keeps track of monster's maximum health value (for re-healing, etc) - - Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) - - int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) - - int m_afCapability;// tells us what a monster can/can't do. - - float m_flNextAttack; // cannot attack again until this time - - int m_bitsDamageType; // what types of damage has monster (player) taken - BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; - - int m_lastDamageAmount;// how much damage did monster (player) last take - // time based damage counters, decr. 1 per 2 seconds - int m_bloodColor; // color of blood particless - - int m_failSchedule; // Schedule type to choose if current schedule fails - - float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. - - float m_flDistTooFar; // if enemy farther away than this, bits_COND_ENEMY_TOOFAR set in CheckEnemy - float m_flDistLook; // distance monster sees (Default 2048) - - int m_iTriggerCondition;// for scripted AI, this is the condition that will cause the activation of the monster's TriggerTarget - string_t m_iszTriggerTarget;// name of target that should be fired. - - Vector m_HackedGunPos; // HACK until we can query end of gun - -// Scripted sequence Info - SCRIPTSTATE m_scriptState; // internal cinematic state - CCineMonster *m_pCine; - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - void KeyValue( KeyValueData *pkvd ); - -// monster use function - void EXPORT MonsterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CorpseUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -// overrideable Monster member functions - - virtual int BloodColor( void ) { return m_bloodColor; } - - virtual CBaseMonster *MyMonsterPointer( void ) { return this; } - virtual void Look ( int iDistance );// basic sight function for monsters - virtual void RunAI ( void );// core ai function! - void Listen ( void ); - - virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } - virtual BOOL ShouldFadeOnDeath( void ); - -// Basic Monster AI functions - virtual float ChangeYaw ( int speed ); - float VecToYaw( Vector vecDir ); - float FlYawDiff ( void ); - - float DamageForce( float damage ); - -// stuff written for new state machine - virtual void MonsterThink( void ); - void EXPORT CallMonsterThink( void ) { this->MonsterThink(); } - virtual int IRelationship ( CBaseEntity *pTarget ); - virtual void MonsterInit ( void ); - virtual void MonsterInitDead( void ); // Call after animation/pose is set up - virtual void BecomeDead( void ); - void EXPORT CorpseFallThink( void ); - - void EXPORT MonsterInitThink ( void ); - virtual void StartMonster ( void ); - virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack - virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone - virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone - virtual void HandleAnimEvent( MonsterEvent_t *pEvent ); - - virtual int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space - virtual void Move( float flInterval = 0.1 ); - virtual void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - virtual BOOL ShouldAdvanceRoute( float flWaypointDist ); - - virtual Activity GetStoppedActivity( void ) { return ACT_IDLE; } - virtual void Stop( void ) { m_IdealActivity = GetStoppedActivity(); } - - // This will stop animation until you call ResetSequenceInfo() at some point in the future - inline void StopAnimation( void ) { pev->framerate = 0; } - - // these functions will survey conditions and set appropriate conditions bits for attack types. - virtual BOOL CheckRangeAttack1( float flDot, float flDist ); - virtual BOOL CheckRangeAttack2( float flDot, float flDist ); - virtual BOOL CheckMeleeAttack1( float flDot, float flDist ); - virtual BOOL CheckMeleeAttack2( float flDot, float flDist ); - - BOOL FHaveSchedule( void ); - BOOL FScheduleValid ( void ); - void ClearSchedule( void ); - BOOL FScheduleDone ( void ); - void ChangeSchedule ( Schedule_t *pNewSchedule ); - void NextScheduledTask ( void ); - Schedule_t *ScheduleInList( const char *pName, Schedule_t **pList, int listCount ); - - virtual Schedule_t *ScheduleFromName( const char *pName ); - static Schedule_t *m_scheduleList[]; - - void MaintainSchedule ( void ); - virtual void StartTask ( Task_t *pTask ); - virtual void RunTask ( Task_t *pTask ); - virtual Schedule_t *GetScheduleOfType( int Type ); - virtual Schedule_t *GetSchedule( void ); - virtual void ScheduleChange( void ) {} - // virtual int CanPlaySequence( void ) { return ((m_pCine == NULL) && (m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE)); } - virtual int CanPlaySequence( BOOL fDisregardState, int interruptLevel ); - virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAlive(); } - virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); - virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - virtual void SentenceStop( void ); - - Task_t *GetTask ( void ); - virtual MONSTERSTATE GetIdealState ( void ); - virtual void SetActivity ( Activity NewActivity ); - void SetSequenceByName ( const char *szSequence ); - void SetState ( MONSTERSTATE State ); - virtual void ReportAIState( void ); - - void CheckAttacks ( CBaseEntity *pTarget, float flDist ); - virtual int CheckEnemy ( CBaseEntity *pEnemy ); - void PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ); - BOOL PopEnemy( void ); - - BOOL FGetNodeRoute ( Vector vecDest ); - - inline void TaskComplete( void ) { if ( !HasConditions(bits_COND_TASK_FAILED) ) m_iTaskStatus = TASKSTATUS_COMPLETE; } - void MovementComplete( void ); - inline void TaskFail( void ) { SetConditions(bits_COND_TASK_FAILED); } - inline void TaskBegin( void ) { m_iTaskStatus = TASKSTATUS_RUNNING; } - int TaskIsRunning( void ); - inline int TaskIsComplete( void ) { return (m_iTaskStatus == TASKSTATUS_COMPLETE); } - inline int MovementIsComplete( void ) { return (m_movementGoal == MOVEGOAL_NONE); } - - int IScheduleFlags ( void ); - BOOL FRefreshRoute( void ); - BOOL FRouteClear ( void ); - void RouteSimplify( CBaseEntity *pTargetEnt ); - void AdvanceRoute ( float distance ); - virtual BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); - void MakeIdealYaw( Vector vecTarget ); - virtual void SetYawSpeed ( void ) { return; };// allows different yaw_speeds for each activity - BOOL BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ); - virtual BOOL BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); - int RouteClassify( int iMoveFlag ); - void InsertWaypoint ( Vector vecLocation, int afMoveFlags ); - - BOOL FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ); - virtual BOOL FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); - virtual BOOL FValidateCover ( const Vector &vecCoverLocation ) { return TRUE; }; - virtual float CoverRadius( void ) { return 784; } // Default cover radius - - virtual BOOL FCanCheckAttacks ( void ); - virtual void CheckAmmo( void ) { return; }; - virtual int IgnoreConditions ( void ); - - inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } - inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } - inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } - inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } - - virtual BOOL FValidateHintType( short sHint ); - int FindHintNode ( void ); - virtual BOOL FCanActiveIdle ( void ); - void SetTurnActivity ( void ); - float FLSoundVolume ( CSound *pSound ); - - BOOL MoveToNode( Activity movementAct, float waitTime, const Vector &goal ); - BOOL MoveToTarget( Activity movementAct, float waitTime ); - BOOL MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ); - BOOL MoveToEnemy( Activity movementAct, float waitTime ); - - // Returns the time when the door will be open - float OpenDoorAndWait( entvars_t *pevDoor ); - - virtual int ISoundMask( void ); - virtual CSound* PBestSound ( void ); - virtual CSound* PBestScent ( void ); - virtual float HearingSensitivity( void ) { return 1.0; }; - - BOOL FBecomeProne ( void ); - virtual void BarnacleVictimBitten( entvars_t *pevBarnacle ); - virtual void BarnacleVictimReleased( void ); - - void SetEyePosition ( void ); - - BOOL FShouldEat( void );// see if a monster is 'hungry' - void Eat ( float flFullDuration );// make the monster 'full' for a while. - - CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); - BOOL FacingIdeal( void ); - - BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. - BOOL NoFriendlyFire( void ); - - BOOL BBoxFlat( void ); - - // PrescheduleThink - virtual void PrescheduleThink( void ) { return; }; - - BOOL GetEnemy ( void ); - void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - // combat functions - float UpdateTarget ( entvars_t *pevTarget ); - virtual Activity GetDeathActivity ( void ); - Activity GetSmallFlinchActivity( void ); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual void GibMonster( void ); - BOOL ShouldGibMonster( int iGib ); - void CallGibMonster( void ); - virtual BOOL HasHumanGibs( void ); - virtual BOOL HasAlienGibs( void ); - virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled - - Vector ShootAtEnemy( const Vector &shootOrigin ); - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) * 0.75 + EyePosition() * 0.25; }; // position to shoot at - - virtual Vector GetGunPosition( void ); - - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - virtual int IsMoving( void ) { return m_movementGoal != MOVEGOAL_NONE; } - - void RouteClear( void ); - void RouteNew( void ); - - virtual void DeathSound ( void ) { return; }; - virtual void AlertSound ( void ) { return; }; - virtual void IdleSound ( void ) { return; }; - virtual void PainSound ( void ) { return; }; - - virtual void StopFollowing( BOOL clearSchedule ) {} - - inline void Remember( int iMemory ) { m_afMemory |= iMemory; } - inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } - inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } - inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } - - BOOL ExitScriptedSequence( ); - BOOL CineCleanup( ); - - CBaseEntity* DropItem ( const char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. -}; - - - -#endif // BASEMONSTER_H diff --git a/sdk/dlls/bigmomma.cpp b/sdk/dlls/bigmomma.cpp deleted file mode 100644 index 224b1e7..0000000 --- a/sdk/dlls/bigmomma.cpp +++ /dev/null @@ -1,1250 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// monster template -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "decals.h" -#include "weapons.h" -#include "game.h" - -#define SF_INFOBM_RUN 0x0001 -#define SF_INFOBM_WAIT 0x0002 - -// AI Nodes for Big Momma -class CInfoBM : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData* pkvd ); - - // name in pev->targetname - // next in pev->target - // radius in pev->scale - // health in pev->health - // Reach target in pev->message - // Reach delay in pev->speed - // Reach sequence in pev->netname - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_preSequence; -}; - -LINK_ENTITY_TO_CLASS( info_bigmomma, CInfoBM ); - -TYPEDESCRIPTION CInfoBM::m_SaveData[] = -{ - DEFINE_FIELD( CInfoBM, m_preSequence, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CInfoBM, CPointEntity ); - -void CInfoBM::Spawn( void ) -{ -} - - -void CInfoBM::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->scale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachdelay")) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachtarget")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "reachsequence")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "presequence")) - { - m_preSequence = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -//========================================================= -// Mortar shot entity -//========================================================= -class CBMortar : public CBaseEntity -{ -public: - void Spawn( void ); - - static CBMortar *Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( bmortar, CBMortar ); - -TYPEDESCRIPTION CBMortar::m_SaveData[] = -{ - DEFINE_FIELD( CBMortar, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBMortar, CBaseEntity ); - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BIG_AE_STEP1 1 // Footstep left -#define BIG_AE_STEP2 2 // Footstep right -#define BIG_AE_STEP3 3 // Footstep back left -#define BIG_AE_STEP4 4 // Footstep back right -#define BIG_AE_SACK 5 // Sack slosh -#define BIG_AE_DEATHSOUND 6 // Death sound - -#define BIG_AE_MELEE_ATTACKBR 8 // Leg attack -#define BIG_AE_MELEE_ATTACKBL 9 // Leg attack -#define BIG_AE_MELEE_ATTACK1 10 // Leg attack -#define BIG_AE_MORTAR_ATTACK1 11 // Launch a mortar -#define BIG_AE_LAY_CRAB 12 // Lay a headcrab -#define BIG_AE_JUMP_FORWARD 13 // Jump up and forward -#define BIG_AE_SCREAM 14 // alert sound -#define BIG_AE_PAIN_SOUND 15 // pain sound -#define BIG_AE_ATTACK_SOUND 16 // attack sound -#define BIG_AE_BIRTH_SOUND 17 // birth sound -#define BIG_AE_EARLY_TARGET 50 // Fire target early - - - -// User defined conditions -#define bits_COND_NODE_SEQUENCE ( bits_COND_SPECIAL1 ) // pev->netname contains the name of a sequence to play - -// Attack distance constants -#define BIG_ATTACKDIST 170 -#define BIG_MORTARDIST 800 -#define BIG_MAXCHILDREN 20 // Max # of live headcrab children - - -#define bits_MEMORY_CHILDPAIR (bits_MEMORY_CUSTOM1) -#define bits_MEMORY_ADVANCE_NODE (bits_MEMORY_CUSTOM2) -#define bits_MEMORY_COMPLETED_NODE (bits_MEMORY_CUSTOM3) -#define bits_MEMORY_FIRED_NODE (bits_MEMORY_CUSTOM4) - -int gSpitSprite, gSpitDebrisSprite; -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ); -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ); - - -// UNDONE: -// -#define BIG_CHILDCLASS "monster_babycrab" - -class CBigMomma : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - void NodeStart( int iszNextNode ); - void NodeReach( void ); - BOOL ShouldGoToNode( void ); - - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void LayHeadcrab( void ); - - int GetNodeSequence( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->netname; // netname holds node sequence - } - return 0; - } - - - int GetNodePresequence( void ) - { - CInfoBM *pTarget = (CInfoBM *)(CBaseEntity *)m_hTargetEnt; - if ( pTarget ) - { - return pTarget->m_preSequence; - } - return 0; - } - - float GetNodeDelay( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->speed; // Speed holds node delay - } - return 0; - } - - float GetNodeRange( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - return pTarget->pev->scale; // Scale holds node delay - } - return 1e6; - } - - float GetNodeYaw( void ) - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget ) - { - if ( pTarget->pev->angles.y != 0 ) - return pTarget->pev->angles.y; - } - return pev->angles.y; - } - - // Restart the crab count on each new level - void OverrideReset( void ) - { - m_crabCount = 0; - } - - void DeathNotice( entvars_t *pevChild ); - - BOOL CanLayCrab( void ) - { - if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN ) - { - // Don't spawn crabs inside each other - Vector mins = pev->origin - Vector( 32, 32, 0 ); - Vector maxs = pev->origin + Vector( 32, 32, 0 ); - - CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - if ( pList[i] != this ) // Don't hurt yourself! - return FALSE; - } - return TRUE; - } - - return FALSE; - } - - void LaunchMortar( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -95, -95, 0 ); - pev->absmax = pev->origin + Vector( 95, 95, 190 ); - } - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Slash - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Lay a crab - BOOL CheckRangeAttack1( float flDot, float flDist ); // Mortar launch - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pChildDieSounds[]; - static const char *pSackSounds[]; - static const char *pDeathSounds[]; - static const char *pAttackSounds[]; - static const char *pAttackHitSounds[]; - static const char *pBirthSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pFootSounds[]; - - CUSTOM_SCHEDULES; - -private: - float m_nodeTime; - float m_crabTime; - float m_mortarTime; - float m_painSoundTime; - int m_crabCount; -}; -LINK_ENTITY_TO_CLASS( monster_bigmomma, CBigMomma ); - -TYPEDESCRIPTION CBigMomma::m_SaveData[] = -{ - DEFINE_FIELD( CBigMomma, m_nodeTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_mortarTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_painSoundTime, FIELD_TIME ), - DEFINE_FIELD( CBigMomma, m_crabCount, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBigMomma, CBaseMonster ); - -const char *CBigMomma::pChildDieSounds[] = -{ - "gonarch/gon_childdie1.wav", - "gonarch/gon_childdie2.wav", - "gonarch/gon_childdie3.wav", -}; - -const char *CBigMomma::pSackSounds[] = -{ - "gonarch/gon_sack1.wav", - "gonarch/gon_sack2.wav", - "gonarch/gon_sack3.wav", -}; - -const char *CBigMomma::pDeathSounds[] = -{ - "gonarch/gon_die1.wav", -}; - -const char *CBigMomma::pAttackSounds[] = -{ - "gonarch/gon_attack1.wav", - "gonarch/gon_attack2.wav", - "gonarch/gon_attack3.wav", -}; -const char *CBigMomma::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CBigMomma::pBirthSounds[] = -{ - "gonarch/gon_birth1.wav", - "gonarch/gon_birth2.wav", - "gonarch/gon_birth3.wav", -}; - -const char *CBigMomma::pAlertSounds[] = -{ - "gonarch/gon_alert1.wav", - "gonarch/gon_alert2.wav", - "gonarch/gon_alert3.wav", -}; - -const char *CBigMomma::pPainSounds[] = -{ - "gonarch/gon_pain2.wav", - "gonarch/gon_pain4.wav", - "gonarch/gon_pain5.wav", -}; - -const char *CBigMomma::pFootSounds[] = -{ - "gonarch/gon_step1.wav", - "gonarch/gon_step2.wav", - "gonarch/gon_step3.wav", -}; - - - -void CBigMomma :: KeyValue( KeyValueData *pkvd ) -{ -#if 0 - if (FStrEq(pkvd->szKeyName, "volume")) - { - m_volume = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else -#endif - CBaseMonster::KeyValue( pkvd ); -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBigMomma :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBigMomma :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 100; - break; - default: - ys = 90; - } - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - case BIG_AE_MELEE_ATTACKBL: - case BIG_AE_MELEE_ATTACK1: - { - Vector forward, right; - - UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); - - Vector center = pev->origin + forward * 128; - Vector mins = center - Vector( 64, 64, 0 ); - Vector maxs = center + Vector( 64, 64, 64 ); - - CBaseEntity *pList[8]; - int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT ); - CBaseEntity *pHurt = NULL; - - for ( int i = 0; i < count && !pHurt; i++ ) - { - if ( pList[i] != this ) - { - if ( pList[i]->pev->owner != edict() ) - pHurt = pList[i]; - } - } - - if ( pHurt ) - { - pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH ); - pHurt->pev->punchangle.x = 15; - switch( pEvent->event ) - { - case BIG_AE_MELEE_ATTACKBR: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200); - break; - - case BIG_AE_MELEE_ATTACKBL: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200); - break; - - case BIG_AE_MELEE_ATTACK1: - pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200); - break; - } - - pHurt->pev->flags &= ~FL_ONGROUND; - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - } - break; - - case BIG_AE_SCREAM: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); - break; - - case BIG_AE_PAIN_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - break; - - case BIG_AE_ATTACK_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds ); - break; - - case BIG_AE_BIRTH_SOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds ); - break; - - case BIG_AE_SACK: - if ( RANDOM_LONG(0,100) < 30 ) - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds ); - break; - - case BIG_AE_DEATHSOUND: - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); - break; - - case BIG_AE_STEP1: // Footstep left - case BIG_AE_STEP3: // Footstep back left - EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds ); - break; - - case BIG_AE_STEP4: // Footstep back right - case BIG_AE_STEP2: // Footstep right - EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds ); - break; - - case BIG_AE_MORTAR_ATTACK1: - LaunchMortar(); - break; - - case BIG_AE_LAY_CRAB: - LayHeadcrab(); - break; - - case BIG_AE_JUMP_FORWARD: - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors ( pev->angles ); - - pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500; - break; - - case BIG_AE_EARLY_TARGET: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( pTarget && pTarget->pev->message ) - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - Remember( bits_MEMORY_FIRED_NODE ); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -void CBigMomma :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if ( ptr->iHitgroup != 1 ) - { - // didn't hit the sack? - - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - else if ( gpGlobals->time > m_painSoundTime ) - { - m_painSoundTime = gpGlobals->time + RANDOM_LONG(1, 3); - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); - } - - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -int CBigMomma :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if ( bitsDamageType & DMG_ACID ) - flDamage = 0; - - if ( !HasMemory(bits_MEMORY_PATH_FINISHED) ) - { - if ( pev->health <= flDamage ) - { - pev->health = flDamage + 1; - Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); - ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); - } - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBigMomma :: LayHeadcrab( void ) -{ - CBaseEntity *pChild = CBaseEntity::Create( BIG_CHILDCLASS, pev->origin, pev->angles, edict() ); - - pChild->pev->spawnflags |= SF_MONSTER_FALL_TO_GROUND; - - // Is this the second crab in a pair? - if ( HasMemory( bits_MEMORY_CHILDPAIR ) ) - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 5, 10 ); - Forget( bits_MEMORY_CHILDPAIR ); - } - else - { - m_crabTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 2.5 ); - Remember( bits_MEMORY_CHILDPAIR ); - } - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,100), ignore_monsters, edict(), &tr); - UTIL_DecalTrace( &tr, DECAL_MOMMABIRTH ); - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBirthSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - m_crabCount++; -} - - - -void CBigMomma::DeathNotice( entvars_t *pevChild ) -{ - if ( m_crabCount > 0 ) // Some babies may cross a transition, but we reset the count then - m_crabCount--; - if ( IsAlive() ) - { - // Make the "my baby's dead" noise! - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pChildDieSounds ); - } -} - - -void CBigMomma::LaunchMortar( void ) -{ - m_mortarTime = gpGlobals->time + RANDOM_FLOAT( 2, 15 ); - - Vector startPos = pev->origin; - startPos.z += 180; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pSackSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - CBMortar *pBomb = CBMortar::Shoot( edict(), startPos, pev->movedir ); - pBomb->pev->gravity = 1.0; - MortarSpray( startPos, Vector(0,0,1), gSpitSprite, 24 ); -} - -//========================================================= -// Spawn -//========================================================= -void CBigMomma :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/big_mom.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 150 * gSkillData.bigmommaHealthFactor; - pev->view_ofs = Vector ( 0, 0, 128 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.3;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBigMomma :: Precache() -{ - PRECACHE_MODEL("models/big_mom.mdl"); - - PRECACHE_SOUND_ARRAY( pChildDieSounds ); - PRECACHE_SOUND_ARRAY( pSackSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pAttackHitSounds ); - PRECACHE_SOUND_ARRAY( pBirthSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pFootSounds ); - - UTIL_PrecacheOther( BIG_CHILDCLASS ); - - // TEMP: Squid - PRECACHE_MODEL("sprites/mommaspit.spr");// spit projectile. - gSpitSprite = PRECACHE_MODEL("sprites/mommaspout.spr");// client side spittle. - gSpitDebrisSprite = PRECACHE_MODEL("sprites/mommablob.spr" ); - - PRECACHE_SOUND( "bullchicken/bc_acid1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit1.wav" ); - PRECACHE_SOUND( "bullchicken/bc_spithit2.wav" ); -} - - -void CBigMomma::Activate( void ) -{ - if ( m_hTargetEnt == 0 ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Start 'er up -} - - -void CBigMomma::NodeStart( int iszNextNode ) -{ - pev->netname = iszNextNode; - - CBaseEntity *pTarget = NULL; - - if ( pev->netname ) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->netname) ); - - if ( !FNullEnt(pentTarget) ) - pTarget = Instance( pentTarget ); - } - - - if ( !pTarget ) - { - ALERT( at_aiconsole, "BM: Finished the path!!\n" ); - Remember( bits_MEMORY_PATH_FINISHED ); - return; - } - Remember( bits_MEMORY_ON_PATH ); - m_hTargetEnt = pTarget; -} - - -void CBigMomma::NodeReach( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - Forget( bits_MEMORY_ADVANCE_NODE ); - - if ( !pTarget ) - return; - - if ( pTarget->pev->health ) - pev->max_health = pev->health = pTarget->pev->health * gSkillData.bigmommaHealthFactor; - - if ( !HasMemory( bits_MEMORY_FIRED_NODE ) ) - { - if ( pTarget->pev->message ) - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - } - Forget( bits_MEMORY_FIRED_NODE ); - - pev->netname = pTarget->pev->target; - if ( pTarget->pev->health == 0 ) - Remember( bits_MEMORY_ADVANCE_NODE ); // Move on if no health at this node -} - - - // Slash -BOOL CBigMomma::CheckMeleeAttack1( float flDot, float flDist ) -{ - if (flDot >= 0.7) - { - if ( flDist <= BIG_ATTACKDIST ) - return TRUE; - } - return FALSE; -} - - -// Lay a crab -BOOL CBigMomma::CheckMeleeAttack2( float flDot, float flDist ) -{ - return CanLayCrab(); -} - - -// Mortar launch -BOOL CBigMomma::CheckRangeAttack1( float flDot, float flDist ) -{ - if ( flDist <= BIG_MORTARDIST && m_mortarTime < gpGlobals->time ) - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy ) - { - Vector startPos = pev->origin; - startPos.z += 180; - pev->movedir = VecCheckSplatToss( pev, startPos, pEnemy->BodyTarget( pev->origin ), RANDOM_FLOAT( 150, 500 ) ); - if ( pev->movedir != g_vecZero ) - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -enum -{ - SCHED_BIG_NODE = LAST_COMMON_SCHEDULE + 1, - SCHED_NODE_FAIL, -}; - -enum -{ - TASK_MOVE_TO_NODE_RANGE = LAST_COMMON_TASK + 1, // Move within node range - TASK_FIND_NODE, // Find my next node - TASK_PLAY_NODE_PRESEQUENCE, // Play node pre-script - TASK_PLAY_NODE_SEQUENCE, // Play node script - TASK_PROCESS_NODE, // Fire targets, etc. - TASK_WAIT_NODE, // Wait at the node - TASK_NODE_DELAY, // Delay walking toward node for a bit. You've failed to get there - TASK_NODE_YAW, // Get the best facing direction for this node -}; - - -Task_t tlBigNode[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_NODE_FAIL }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_NODE, (float)0 }, // Find my next node - { TASK_PLAY_NODE_PRESEQUENCE,(float)0 }, // Play the pre-approach sequence if any - { TASK_MOVE_TO_NODE_RANGE, (float)0 }, // Move within node range - { TASK_STOP_MOVING, (float)0 }, - { TASK_NODE_YAW, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_NODE, (float)0 }, // Wait for node delay - { TASK_PLAY_NODE_SEQUENCE, (float)0 }, // Play the sequence if one exists - { TASK_PROCESS_NODE, (float)0 }, // Fire targets, etc. - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slBigNode[] = -{ - { - tlBigNode, - ARRAYSIZE ( tlBigNode ), - 0, - 0, - "Big Node" - }, -}; - - -Task_t tlNodeFail[] = -{ - { TASK_NODE_DELAY, (float)10 }, // Try to do something else for 10 seconds - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slNodeFail[] = -{ - { - tlNodeFail, - ARRAYSIZE ( tlNodeFail ), - 0, - 0, - "NodeFail" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CBigMomma ) -{ - slBigNode, - slNodeFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBigMomma, CBaseMonster ); - - - - -Schedule_t *CBigMomma::GetScheduleOfType( int Type ) -{ - switch( Type ) - { - case SCHED_BIG_NODE: - return slBigNode; - break; - - case SCHED_NODE_FAIL: - return slNodeFail; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -BOOL CBigMomma::ShouldGoToNode( void ) -{ - if ( HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if ( m_nodeTime < gpGlobals->time ) - return TRUE; - } - return FALSE; -} - - - -Schedule_t *CBigMomma::GetSchedule( void ) -{ - if ( ShouldGoToNode() ) - { - return GetScheduleOfType( SCHED_BIG_NODE ); - } - - return CBaseMonster::GetSchedule(); -} - - -void CBigMomma::StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_FIND_NODE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( !HasMemory( bits_MEMORY_ADVANCE_NODE ) ) - { - if ( pTarget ) - pev->netname = m_hTargetEnt->pev->target; - } - NodeStart( pev->netname ); - TaskComplete(); - ALERT( at_aiconsole, "BM: Found node %s\n", STRING(pev->netname) ); - } - break; - - case TASK_NODE_DELAY: - m_nodeTime = gpGlobals->time + pTask->flData; - TaskComplete(); - ALERT( at_aiconsole, "BM: FAIL! Delay %.2f\n", pTask->flData ); - break; - - case TASK_PROCESS_NODE: - ALERT( at_aiconsole, "BM: Reached node %s\n", STRING(pev->netname) ); - NodeReach(); - TaskComplete(); - break; - - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - { - int sequence; - if ( pTask->iTask == TASK_PLAY_NODE_SEQUENCE ) - sequence = GetNodeSequence(); - else - sequence = GetNodePresequence(); - - ALERT( at_aiconsole, "BM: Playing node sequence %s\n", STRING(sequence) ); - if ( sequence ) - { - sequence = LookupSequence( STRING( sequence ) ); - if ( sequence != -1 ) - { - pev->sequence = sequence; - pev->frame = 0; - ResetSequenceInfo( ); - ALERT( at_aiconsole, "BM: Sequence %s\n", STRING(GetNodeSequence()) ); - return; - } - } - TaskComplete(); - } - break; - - case TASK_NODE_YAW: - pev->ideal_yaw = GetNodeYaw(); - TaskComplete(); - break; - - case TASK_WAIT_NODE: - m_flWait = gpGlobals->time + GetNodeDelay(); - if ( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT ) - ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING(pev->netname) ); - else - ALERT( at_aiconsole, "BM: Wait at node %s for %.2f\n", STRING(pev->netname), GetNodeDelay() ); - break; - - - case TASK_MOVE_TO_NODE_RANGE: - { - CBaseEntity *pTarget = m_hTargetEnt; - if ( !pTarget ) - TaskFail(); - else - { - if ( (pTarget->pev->origin - pev->origin).Length() < GetNodeRange() ) - TaskComplete(); - else - { - Activity act = ACT_WALK; - if ( pTarget->pev->spawnflags & SF_INFOBM_RUN ) - act = ACT_RUN; - - m_vecMoveGoal = pTarget->pev->origin; - if ( !MoveToTarget( act, 2 ) ) - { - TaskFail(); - } - } - } - } - ALERT( at_aiconsole, "BM: Moving to node %s\n", STRING(pev->netname) ); - - break; - - case TASK_MELEE_ATTACK1: - // Play an attack sound here - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), 1.0, ATTN_NORM, 0, PITCH_NORM ); - CBaseMonster::StartTask( pTask ); - break; - - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CBigMomma::RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_MOVE_TO_NODE_RANGE: - { - float distance; - - if ( m_hTargetEnt == 0 ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( (distance < GetNodeRange()) || MovementIsComplete() ) - { - ALERT( at_aiconsole, "BM: Reached node!\n" ); - TaskComplete(); - RouteClear(); // Stop moving - } - } - } - - break; - - case TASK_WAIT_NODE: - if ( m_hTargetEnt != 0 && (m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT) ) - return; - - if ( gpGlobals->time > m_flWaitFinished ) - TaskComplete(); - ALERT( at_aiconsole, "BM: The WAIT is over!\n" ); - break; - - case TASK_PLAY_NODE_PRESEQUENCE: - case TASK_PLAY_NODE_SEQUENCE: - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - - - -Vector VecCheckSplatToss( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float maxHeight ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = g_psv_gravity->value; - - // calculate the midpoint and apex of the 'triangle' - vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,maxHeight), ignore_monsters, ENT(pev), &tr); - vecApex = tr.vecEndPos; - - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - // Don't worry about actually hitting the target, this won't hurt us! - - // How high should the grenade travel (subtract 15 so the grenade doesn't hit the ceiling)? - float height = (vecApex.z - vecSpot1.z) - 15; - // How fast does the grenade need to travel to reach that height given gravity? - float speed = sqrt( 2 * flGravity * height ); - - // How much time does it take to get there? - float time = speed / flGravity; - vecGrenadeVel = (vecSpot2 - vecSpot1); - vecGrenadeVel.z = 0; - - // Travel half the distance to the target in that time (apex is at the midpoint) - vecGrenadeVel = vecGrenadeVel * ( 0.5 / time ); - // Speed to offset gravity at the desired height - vecGrenadeVel.z = speed; - - return vecGrenadeVel; -} - - - - -// --------------------------------- -// -// Mortar -// -// --------------------------------- -void MortarSpray( const Vector &position, const Vector &direction, int spriteModel, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( position.x); // pos - WRITE_COORD( position.y); - WRITE_COORD( position.z); - WRITE_COORD( direction.x); // dir - WRITE_COORD( direction.y); - WRITE_COORD( direction.z); - WRITE_SHORT( spriteModel ); // model - WRITE_BYTE ( count ); // count - WRITE_BYTE ( 130 ); // speed - WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); -} - - -// UNDONE: right now this is pretty much a copy of the squid spit with minor changes to the way it does damage -void CBMortar:: Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->classname = MAKE_STRING( "bmortar" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/mommaspit.spr"); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - pev->dmgtime = gpGlobals->time + 0.4; -} - -void CBMortar::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( gpGlobals->time > pev->dmgtime ) - { - pev->dmgtime = gpGlobals->time + 0.2; - MortarSpray( pev->origin, -pev->velocity.Normalize(), gSpitSprite, 3 ); - } - if ( pev->frame++ ) - { - if ( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -CBMortar *CBMortar::Shoot( edict_t *pOwner, Vector vecStart, Vector vecVelocity ) -{ - CBMortar *pSpit = GetClassPtr( (CBMortar *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = pOwner; - pSpit->pev->scale = 2.5; - pSpit->SetThink ( &CBMortar::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; - - return pSpit; -} - - -void CBMortar::Touch( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if ( pOther->IsBSPModel() ) - { - - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace(&tr, DECAL_MOMMASPLAT); - } - else - { - tr.vecEndPos = pev->origin; - tr.vecPlaneNormal = -1 * pev->velocity.Normalize(); - } - // make some flecks - MortarSpray( tr.vecEndPos, tr.vecPlaneNormal, gSpitSprite, 24 ); - - entvars_t *pevOwner = NULL; - if ( pev->owner ) - pevOwner = VARS(pev->owner); - - RadiusDamage( pev->origin, pev, pevOwner, gSkillData.bigmommaDmgBlast, gSkillData.bigmommaRadiusBlast, CLASS_NONE, DMG_ACID ); - UTIL_Remove( this ); -} - -#endif diff --git a/sdk/dlls/bloater.cpp b/sdk/dlls/bloater.cpp deleted file mode 100644 index eb0c734..0000000 --- a/sdk/dlls/bloater.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Bloater -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BLOATER_AE_ATTACK_MELEE1 0x01 - - -class CBloater : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSnd( void ); - - // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_bloater, CBloater ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBloater :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBloater :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CBloater :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CBloater :: PainSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,5)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_pain2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - default: - break; - } -#endif -} - -void CBloater :: AlertSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,2)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert10.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert20.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_alert30.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - -void CBloater :: IdleSound( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,2)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_idle3.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - -void CBloater :: AttackSnd( void ) -{ -#if 0 - int pitch = 95 + RANDOM_LONG(0,9); - - switch (RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack1.wav", 1.0, ATTN_NORM, 0, pitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "zombie/zo_attack2.wav", 1.0, ATTN_NORM, 0, pitch); - break; - } -#endif -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBloater :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BLOATER_AE_ATTACK_MELEE1: - { - // do stuff for this event. - AttackSnd(); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CBloater :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/floater.mdl"); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->spawnflags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 40; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBloater :: Precache() -{ - PRECACHE_MODEL("models/floater.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - diff --git a/sdk/dlls/bmodels.cpp b/sdk/dlls/bmodels.cpp deleted file mode 100644 index 7feccf3..0000000 --- a/sdk/dlls/bmodels.cpp +++ /dev/null @@ -1,958 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -#define SF_BRUSH_ACCDCC 16// brush should accelerate and decelerate when toggled -#define SF_BRUSH_HURT 32// rotating brush that inflicts pain based on rotation speed -#define SF_ROTATING_NOT_SOLID 64 // some special rotating objects are not solid. - -// covering cheesy noise1, noise2, & noise3 fields so they make more sense (for rotating fans) -#define noiseStart noise1 -#define noiseStop noise2 -#define noiseRunning noise3 - -#define SF_PENDULUM_SWING 2 // spawnflag that makes a pendulum a rope swing. -// -// BModelOrigin - calculates origin of a bmodel from absmin/size because all bmodel origins are 0 0 0 -// -Vector VecBModelOrigin( entvars_t* pevBModel ) -{ - return pevBModel->absmin + ( pevBModel->size * 0.5 ); -} - -// =================== FUNC_WALL ============================================== - -/*QUAKED func_wall (0 .5 .8) ? -This is just a solid wall if not inhibited -*/ -class CFuncWall : public CBaseEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -LINK_ENTITY_TO_CLASS( func_wall, CFuncWall ); - -void CFuncWall :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - // If it can't move/go away, it's really part of the world - pev->flags |= FL_WORLDBRUSH; -} - - -void CFuncWall :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, (int)(pev->frame)) ) - pev->frame = 1 - pev->frame; -} - - -#define SF_WALL_START_OFF 0x0001 - -class CFuncWallToggle : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void TurnOff( void ); - void TurnOn( void ); - BOOL IsOn( void ); -}; - -LINK_ENTITY_TO_CLASS( func_wall_toggle, CFuncWallToggle ); - -void CFuncWallToggle :: Spawn( void ) -{ - CFuncWall::Spawn(); - if ( pev->spawnflags & SF_WALL_START_OFF ) - TurnOff(); -} - - -void CFuncWallToggle :: TurnOff( void ) -{ - pev->solid = SOLID_NOT; - pev->effects |= EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -void CFuncWallToggle :: TurnOn( void ) -{ - pev->solid = SOLID_BSP; - pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( pev, pev->origin ); -} - - -BOOL CFuncWallToggle :: IsOn( void ) -{ - if ( pev->solid == SOLID_NOT ) - return FALSE; - return TRUE; -} - - -void CFuncWallToggle :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int status = IsOn(); - - if ( ShouldToggle( useType, status ) ) - { - if ( status ) - TurnOff(); - else - TurnOn(); - } -} - - -#define SF_CONVEYOR_VISUAL 0x0001 -#define SF_CONVEYOR_NOTSOLID 0x0002 - -class CFuncConveyor : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void UpdateSpeed( float speed ); -}; - -LINK_ENTITY_TO_CLASS( func_conveyor, CFuncConveyor ); -void CFuncConveyor :: Spawn( void ) -{ - SetMovedir( pev ); - CFuncWall::Spawn(); - - if ( !(pev->spawnflags & SF_CONVEYOR_VISUAL) ) - SetBits( pev->flags, FL_CONVEYOR ); - - // HACKHACK - This is to allow for some special effects - if ( pev->spawnflags & SF_CONVEYOR_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->skin = 0; // Don't want the engine thinking we've got special contents on this brush - } - - if ( pev->speed == 0 ) - pev->speed = 100; - - UpdateSpeed( pev->speed ); -} - - -// HACKHACK -- This is ugly, but encode the speed in the rendercolor to avoid adding more data to the network stream -void CFuncConveyor :: UpdateSpeed( float speed ) -{ - // Encode it as an integer with 4 fractional bits - int speedCode = (int)(fabs(speed) * 16.0); - - if ( speed < 0 ) - pev->rendercolor.x = 1; - else - pev->rendercolor.x = 0; - - pev->rendercolor.y = (speedCode >> 8); - pev->rendercolor.z = (speedCode & 0xFF); -} - - -void CFuncConveyor :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->speed = -pev->speed; - UpdateSpeed( pev->speed ); -} - - - -// =================== FUNC_ILLUSIONARY ============================================== - - -/*QUAKED func_illusionary (0 .5 .8) ? -A simple entity that looks solid but lets you walk through it. -*/ -class CFuncIllusionary : public CBaseToggle -{ -public: - void Spawn( void ); - void EXPORT SloshTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -LINK_ENTITY_TO_CLASS( func_illusionary, CFuncIllusionary ); - -void CFuncIllusionary :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CFuncIllusionary :: Spawn( void ) -{ - pev->angles = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT;// always solid_not - SET_MODEL( ENT(pev), STRING(pev->model) ); - - // I'd rather eat the network bandwidth of this than figure out how to save/restore - // these entities after they have been moved to the client, or respawn them ala Quake - // Perhaps we can do this in deathmatch only. - // MAKE_STATIC(ENT(pev)); -} - - -// ------------------------------------------------------------------------------- -// -// Monster only clip brush -// -// This brush will be solid for any entity who has the FL_MONSTERCLIP flag set -// in pev->flags -// -// otherwise it will be invisible and not solid. This can be used to keep -// specific monsters out of certain areas -// -// ------------------------------------------------------------------------------- -class CFuncMonsterClip : public CFuncWall -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {} // Clear out func_wall's use function -}; - -LINK_ENTITY_TO_CLASS( func_monsterclip, CFuncMonsterClip ); - -void CFuncMonsterClip::Spawn( void ) -{ - CFuncWall::Spawn(); - if ( CVAR_GET_FLOAT("showtriggers") == 0 ) - pev->effects = EF_NODRAW; - pev->flags |= FL_MONSTERCLIP; -} - - -// =================== FUNC_ROTATING ============================================== -class CFuncRotating : public CBaseEntity -{ -public: - // basic functions - void Spawn( void ); - void Precache( void ); - void EXPORT SpinUp ( void ); - void EXPORT SpinDown ( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT HurtTouch ( CBaseEntity *pOther ); - void EXPORT RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Rotate( void ); - void RampPitchVol (int fUp ); - void Blocked( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flFanFriction; - float m_flAttenuation; - float m_flVolume; - float m_pitch; - int m_sounds; -}; - -TYPEDESCRIPTION CFuncRotating::m_SaveData[] = -{ - DEFINE_FIELD( CFuncRotating, m_flFanFriction, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_pitch, FIELD_FLOAT ), - DEFINE_FIELD( CFuncRotating, m_sounds, FIELD_INTEGER ) -}; - -IMPLEMENT_SAVERESTORE( CFuncRotating, CBaseEntity ); - - -LINK_ENTITY_TO_CLASS( func_rotating, CFuncRotating ); - -void CFuncRotating :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "fanfriction")) - { - m_flFanFriction = atof(pkvd->szValue)/100; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Volume")) - { - m_flVolume = atof(pkvd->szValue)/10.0; - - if (m_flVolume > 1.0) - m_flVolume = 1.0; - if (m_flVolume < 0.0) - m_flVolume = 0.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnorigin")) - { - Vector tmp; - UTIL_StringToVector( (float *)tmp, pkvd->szValue ); - if ( tmp != g_vecZero ) - pev->origin = tmp; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -/*QUAKED func_rotating (0 .5 .8) ? START_ON REVERSE X_AXIS Y_AXIS -You need to have an origin brush as part of this entity. The -center of that brush will be -the point around which it is rotated. It will rotate around the Z -axis by default. You can -check either the X_AXIS or Y_AXIS box to change that. - -"speed" determines how fast it moves; default value is 100. -"dmg" damage to inflict when blocked (2 default) - -REVERSE will cause the it to rotate in the opposite direction. -*/ - - -void CFuncRotating :: Spawn( ) -{ - // set final pitch. Must not be PITCH_NORM, since we - // plan on pitch shifting later. - - m_pitch = PITCH_NORM - 1; - - // maintain compatibility with previous maps - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - // if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_NORM; - - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, SF_BRUSH_ROTATE_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - - // prevent divide by zero if level designer forgets friction! - if ( m_flFanFriction == 0 ) - { - m_flFanFriction = 1; - } - - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_Z_AXIS) ) - pev->movedir = Vector(0,0,1); - else if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_X_AXIS) ) - pev->movedir = Vector(1,0,0); - else - pev->movedir = Vector(0,1,0); // y-axis - - // check for reverse rotation - if ( FBitSet(pev->spawnflags, SF_BRUSH_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - // some rotating objects like fake volumetric lights will not be solid. - if ( FBitSet(pev->spawnflags, SF_ROTATING_NOT_SOLID) ) - { - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_EMPTY; - pev->movetype = MOVETYPE_PUSH; - } - else - { - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - } - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - SetUse( &CFuncRotating::RotatingUse ); - // did level designer forget to assign speed? - if (pev->speed <= 0) - pev->speed = 0; - - // Removed this per level designers request. -- JAY - // if (pev->dmg == 0) - // pev->dmg = 2; - - // instant-use brush? - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CFuncRotating::SUB_CallUseToggle ); - pev->nextthink = pev->ltime + 1.5; // leave a magic delay for client to start up - } - // can this brush inflict pain? - if ( FBitSet (pev->spawnflags, SF_BRUSH_HURT) ) - { - SetTouch( &CFuncRotating::HurtTouch ); - } - - Precache( ); -} - - -void CFuncRotating :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - // set up fan sounds - - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - // if a path is set for a wave, use it - - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - } else - { - // otherwise use preset sound - switch (m_sounds) - { - case 1: - PRECACHE_SOUND ("fans/fan1.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan1.wav"); - break; - case 2: - PRECACHE_SOUND ("fans/fan2.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan2.wav"); - break; - case 3: - PRECACHE_SOUND ("fans/fan3.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan3.wav"); - break; - case 4: - PRECACHE_SOUND ("fans/fan4.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan4.wav"); - break; - case 5: - PRECACHE_SOUND ("fans/fan5.wav"); - pev->noiseRunning = ALLOC_STRING("fans/fan5.wav"); - break; - - case 0: - default: - if (!FStringNull( pev->message ) && strlen( szSoundFile ) > 0) - { - PRECACHE_SOUND(szSoundFile); - - pev->noiseRunning = ALLOC_STRING(szSoundFile); - break; - } else - { - pev->noiseRunning = ALLOC_STRING("common/null.wav"); - break; - } - } - } - - if (pev->avelocity != g_vecZero ) - { - // if fan was spinning, and we went through transition or save/restore, - // make sure we restart the sound. 1.5 sec delay is magic number. KDB - - SetThink ( &CFuncRotating::SpinUp ); - pev->nextthink = pev->ltime + 1.5; - } -} - - - -// -// Touch - will hurt others based on how fast the brush is spinning -// -void CFuncRotating :: HurtTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - pev->dmg = pev->avelocity.Length() / 10; - - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * pev->dmg; -} - -// -// RampPitchVol - ramp pitch and volume up to final values, based on difference -// between how fast we're going vs how fast we plan to go -// -#define FANPITCHMIN 30 -#define FANPITCHMAX 100 - -void CFuncRotating :: RampPitchVol (int fUp) -{ - - Vector vecAVel = pev->avelocity; - vec_t vecCur; - vec_t vecFinal; - float fpct; - float fvol; - float fpitch; - int pitch; - - // get current angular velocity - - vecCur = abs(vecAVel.x != 0 ? static_cast(vecAVel.x) : static_cast(vecAVel.y != 0 ? vecAVel.y : vecAVel.z)); - - // get target angular velocity - - vecFinal = (pev->movedir.x != 0 ? pev->movedir.x : (pev->movedir.y != 0 ? pev->movedir.y : pev->movedir.z)); - vecFinal *= pev->speed; - vecFinal = abs(static_cast(vecFinal)); - - // calc volume and pitch as % of final vol and pitch - - fpct = vecCur / vecFinal; -// if (fUp) -// fvol = m_flVolume * (0.5 + fpct/2.0); // spinup volume ramps up from 50% max vol -// else - fvol = m_flVolume * fpct; // slowdown volume ramps down to 0 - - fpitch = FANPITCHMIN + (FANPITCHMAX - FANPITCHMIN) * fpct; - - pitch = (int) fpitch; - if (pitch == PITCH_NORM) - pitch = PITCH_NORM-1; - - // change the fan's vol and pitch - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - fvol, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - -} - -// -// SpinUp - accelerates a non-moving func_rotating up to it's speed -// -void CFuncRotating :: SpinUp( void ) -{ - Vector vecAVel;//rotational velocity - - pev->nextthink = pev->ltime + 0.1; - pev->avelocity = pev->avelocity + ( pev->movedir * ( pev->speed * m_flFanFriction ) ); - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - // if we've met or exceeded target speed, set target speed and stop thinking - if ( abs(static_cast(vecAVel.x)) >= abs(static_cast(pev->movedir.x * pev->speed)) && - abs(static_cast(vecAVel.y)) >= abs(static_cast(pev->movedir.y * pev->speed)) && - abs(static_cast(vecAVel.z)) >= abs(static_cast(pev->movedir.z * pev->speed)) ) - { - pev->avelocity = pev->movedir * pev->speed;// set speed in case we overshot - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, SND_CHANGE_PITCH | SND_CHANGE_VOL, FANPITCHMAX); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(TRUE); - } -} - -// -// SpinDown - decelerates a moving func_rotating to a standstill. -// -void CFuncRotating :: SpinDown( void ) -{ - Vector vecAVel;//rotational velocity - vec_t vecdir; - - pev->nextthink = pev->ltime + 0.1; - - pev->avelocity = pev->avelocity - ( pev->movedir * ( pev->speed * m_flFanFriction ) );//spin down slower than spinup - - vecAVel = pev->avelocity;// cache entity's rotational velocity - - if (pev->movedir.x != 0) - vecdir = pev->movedir.x; - else if (pev->movedir.y != 0) - vecdir = pev->movedir.y; - else - vecdir = pev->movedir.z; - - // if we've met or exceeded target speed, set target speed and stop thinking - // (note: must check for movedir > 0 or < 0) - if (((vecdir > 0) && (vecAVel.x <= 0 && vecAVel.y <= 0 && vecAVel.z <= 0)) || - ((vecdir < 0) && (vecAVel.x >= 0 && vecAVel.y >= 0 && vecAVel.z >= 0))) - { - pev->avelocity = g_vecZero;// set speed in case we overshot - - // stop sound, we're done - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning /* Stop */), - 0, 0, SND_STOP, static_cast(m_pitch)); - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - else - { - RampPitchVol(FALSE); - } -} - -void CFuncRotating :: Rotate( void ) -{ - pev->nextthink = pev->ltime + 10; -} - -//========================================================= -// Rotating Use - when a rotating brush is triggered -//========================================================= -void CFuncRotating :: RotatingUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // is this a brush that should accelerate and decelerate when turned on/off (fan)? - if ( FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) ) - { - // fan is spinning, so stop it. - if ( pev->avelocity != g_vecZero ) - { - SetThink ( &CFuncRotating::SpinDown ); - //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - } - else// fan is not moving, so start it - { - SetThink ( &CFuncRotating::SpinUp ); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - 0.01, m_flAttenuation, 0, FANPITCHMIN); - - pev->nextthink = pev->ltime + 0.1; - } - } - else if ( !FBitSet ( pev->spawnflags, SF_BRUSH_ACCDCC ) )//this is a normal start/stop brush. - { - if ( pev->avelocity != g_vecZero ) - { - // play stopping sound here - SetThink ( &CFuncRotating::SpinDown ); - - // EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, (char *)STRING(pev->noiseStop), - // m_flVolume, m_flAttenuation, 0, m_pitch); - - pev->nextthink = pev->ltime + 0.1; - // pev->avelocity = g_vecZero; - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char *)STRING(pev->noiseRunning), - m_flVolume, m_flAttenuation, 0, FANPITCHMAX); - pev->avelocity = pev->movedir * pev->speed; - - SetThink( &CFuncRotating::Rotate ); - Rotate(); - } - } -} - - -// -// RotatingBlocked - An entity has blocked the brush -// -void CFuncRotating :: Blocked( CBaseEntity *pOther ) - -{ - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH); -} - - - - - - -//#endif - - -class CPendulum : public CBaseEntity -{ -public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT Swing( void ); - void EXPORT PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Stop( void ); - void Touch( CBaseEntity *pOther ); - void EXPORT RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void Blocked( CBaseEntity *pOther ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_accel; // Acceleration - float m_distance; // - float m_time; - float m_damp; - float m_maxSpeed; - float m_dampSpeed; - vec3_t m_center; - vec3_t m_start; -}; - -LINK_ENTITY_TO_CLASS( func_pendulum, CPendulum ); - -TYPEDESCRIPTION CPendulum::m_SaveData[] = -{ - DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ), - DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ), - DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity ); - - - -void CPendulum :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "distance")) - { - m_distance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damp")) - { - m_damp = atof(pkvd->szValue) * 0.001; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CPendulum :: Spawn( void ) -{ - // set the axis of rotation - CBaseToggle :: AxisDir( pev ); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( m_distance == 0 ) - return; - - if (pev->speed == 0) - pev->speed = 100; - - m_accel = (pev->speed * pev->speed) / (2 * fabs(m_distance)); // Calculate constant acceleration from speed and distance - m_maxSpeed = pev->speed; - m_start = pev->angles; - m_center = pev->angles + (m_distance * 0.5) * pev->movedir; - - if ( FBitSet( pev->spawnflags, SF_BRUSH_ROTATE_INSTANT) ) - { - SetThink( &CPendulum::SUB_CallUseToggle ); - pev->nextthink = gpGlobals->time + 0.1; - } - pev->speed = 0; - SetUse( &CPendulum::PendulumUse ); - - if ( FBitSet( pev->spawnflags, SF_PENDULUM_SWING ) ) - { - SetTouch ( &CPendulum::RopeTouch ); - } -} - - -void CPendulum :: PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->speed ) // Pendulum is moving, stop it and auto-return if necessary - { - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) ) - { - float delta; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_start ); - - pev->avelocity = m_maxSpeed * pev->movedir; - pev->nextthink = pev->ltime + (delta / m_maxSpeed); - SetThink( &CPendulum::Stop ); - } - else - { - pev->speed = 0; // Dead stop - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - } - else - { - pev->nextthink = pev->ltime + 0.1; // Start the pendulum moving - m_time = gpGlobals->time; // Save time to calculate dt - SetThink( &CPendulum::Swing ); - m_dampSpeed = m_maxSpeed; - } -} - - -void CPendulum :: Stop( void ) -{ - pev->angles = m_start; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; -} - - -void CPendulum::Blocked( CBaseEntity *pOther ) -{ - m_time = gpGlobals->time; -} - - -void CPendulum :: Swing( void ) -{ - float delta, dt; - - delta = CBaseToggle :: AxisDelta( pev->spawnflags, pev->angles, m_center ); - dt = gpGlobals->time - m_time; // How much time has passed? - m_time = gpGlobals->time; // Remember the last time called - - if ( delta > 0 && m_accel > 0 ) - pev->speed -= m_accel * dt; // Integrate velocity - else - pev->speed += m_accel * dt; - - if ( pev->speed > m_maxSpeed ) - pev->speed = m_maxSpeed; - else if ( pev->speed < -m_maxSpeed ) - pev->speed = -m_maxSpeed; - // scale the destdelta vector by the time spent traveling to get velocity - pev->avelocity = pev->speed * pev->movedir; - - // Call this again - pev->nextthink = pev->ltime + 0.1; - - if ( m_damp ) - { - m_dampSpeed -= m_damp * m_dampSpeed * dt; - if ( m_dampSpeed < 30.0 ) - { - pev->angles = m_center; - pev->speed = 0; - SetThink( NULL ); - pev->avelocity = g_vecZero; - } - else if ( pev->speed > m_dampSpeed ) - pev->speed = m_dampSpeed; - else if ( pev->speed < -m_dampSpeed ) - pev->speed = -m_dampSpeed; - - } -} - - -void CPendulum :: Touch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( pev->dmg <= 0 ) - return; - - // we can't hurt this thing, so we're not concerned with it - if ( !pevOther->takedamage ) - return; - - // calculate damage based on rotation speed - float damage = pev->dmg * pev->speed * 0.01; - - if ( damage < 0 ) - damage = -damage; - - pOther->TakeDamage( pev, pev, damage, DMG_CRUSH ); - - pevOther->velocity = (pevOther->origin - VecBModelOrigin(pev) ).Normalize() * damage; -} - -void CPendulum :: RopeTouch ( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !pOther->IsPlayer() ) - {// not a player! - ALERT ( at_console, "Not a client\n" ); - return; - } - - if ( ENT(pevOther) == pev->enemy ) - {// this player already on the rope. - return; - } - - pev->enemy = pOther->edict(); - pevOther->velocity = g_vecZero; - pevOther->movetype = MOVETYPE_NONE; -} - - diff --git a/sdk/dlls/bullsquid.cpp b/sdk/dlls/bullsquid.cpp deleted file mode 100644 index 148d4dd..0000000 --- a/sdk/dlls/bullsquid.cpp +++ /dev/null @@ -1,1279 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// bullsquid - big, spotty tentacle-mouthed meanie. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "nodes.h" -#include "effects.h" -#include "decals.h" -#include "soundent.h" -#include "game.h" - -#define SQUID_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve - -int iSquidSpitSprite; - - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_SQUID_HURTHOP = LAST_COMMON_SCHEDULE + 1, - SCHED_SQUID_SMELLFOOD, - SCHED_SQUID_SEECRAB, - SCHED_SQUID_EAT, - SCHED_SQUID_SNIFF_AND_EAT, - SCHED_SQUID_WALLOW, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_SQUID_HOPTURN = LAST_COMMON_TASK + 1, -}; - -//========================================================= -// Bullsquid's spit projectile -//========================================================= -class CSquidSpit : public CBaseEntity -{ -public: - void Spawn( void ); - - static void Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - void Touch( CBaseEntity *pOther ); - void EXPORT Animate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( squidspit, CSquidSpit ); - -TYPEDESCRIPTION CSquidSpit::m_SaveData[] = -{ - DEFINE_FIELD( CSquidSpit, m_maxFrame, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSquidSpit, CBaseEntity ); - -void CSquidSpit:: Spawn( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->classname = MAKE_STRING( "squidspit" ); - - pev->solid = SOLID_BBOX; - pev->rendermode = kRenderTransAlpha; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/bigspit.spr"); - pev->frame = 0; - pev->scale = 0.5; - - UTIL_SetSize( pev, Vector( 0, 0, 0), Vector(0, 0, 0) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; -} - -void CSquidSpit::Animate( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( pev->frame++ ) - { - if ( pev->frame > m_maxFrame ) - { - pev->frame = 0; - } - } -} - -void CSquidSpit::Shoot( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CSquidSpit *pSpit = GetClassPtr( (CSquidSpit *)NULL ); - pSpit->Spawn(); - - UTIL_SetOrigin( pSpit->pev, vecStart ); - pSpit->pev->velocity = vecVelocity; - pSpit->pev->owner = ENT(pevOwner); - - pSpit->SetThink ( &CSquidSpit::Animate ); - pSpit->pev->nextthink = gpGlobals->time + 0.1; -} - -void CSquidSpit :: Touch ( CBaseEntity *pOther ) -{ - TraceResult tr; - int iPitch; - - // splat sound - iPitch = RANDOM_FLOAT( 90, 110 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_acid1.wav", 1, ATTN_NORM, 0, iPitch ); - - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_spithit2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - if ( !pOther->pev->takedamage ) - { - - // make a splat on the wall - UTIL_TraceLine( pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT( pev ), &tr ); - UTIL_DecalTrace(&tr, DECAL_SPIT1 + RANDOM_LONG(0,1)); - - // make some flecks - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, tr.vecEndPos ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( tr.vecEndPos.x); // pos - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_COORD( tr.vecPlaneNormal.x); // dir - WRITE_COORD( tr.vecPlaneNormal.y); - WRITE_COORD( tr.vecPlaneNormal.z); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE ( 5 ); // count - WRITE_BYTE ( 30 ); // speed - WRITE_BYTE ( 80 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - } - else - { - pOther->TakeDamage ( pev, pev, gSkillData.bullsquidDmgSpit, DMG_GENERIC ); - } - - SetThink ( &CSquidSpit::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define BSQUID_AE_SPIT ( 1 ) -#define BSQUID_AE_BITE ( 2 ) -#define BSQUID_AE_BLINK ( 3 ) -#define BSQUID_AE_TAILWHIP ( 4 ) -#define BSQUID_AE_HOP ( 5 ) -#define BSQUID_AE_THROW ( 6 ) - -class CBullsquid : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void IdleSound( void ); - void PainSound( void ); - void DeathSound( void ); - void AlertSound ( void ); - void AttackSound( void ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckMeleeAttack2 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - void RunAI( void ); - BOOL FValidateHintType ( short sHint ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int IRelationship ( CBaseEntity *pTarget ); - int IgnoreConditions ( void ); - MONSTERSTATE GetIdealState ( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - BOOL m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time. - - float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while. - float m_flNextSpitTime;// last time the bullsquid used the spit attack. -}; -LINK_ENTITY_TO_CLASS( monster_bullchicken, CBullsquid ); - -TYPEDESCRIPTION CBullsquid::m_SaveData[] = -{ - DEFINE_FIELD( CBullsquid, m_fCanThreatDisplay, FIELD_BOOLEAN ), - DEFINE_FIELD( CBullsquid, m_flLastHurtTime, FIELD_TIME ), - DEFINE_FIELD( CBullsquid, m_flNextSpitTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBullsquid, CBaseMonster ); - -//========================================================= -// IgnoreConditions -//========================================================= -int CBullsquid::IgnoreConditions ( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if ( gpGlobals->time - m_flLastHurtTime <= 20 ) - { - // haven't been hurt in 20 seconds, so let the squid care about stink. - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - - if ( m_hEnemy != 0 ) - { - if ( FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // (Unless after a tasty headcrab) - iIgnore = bits_COND_SMELL | bits_COND_SMELL_FOOD; - } - } - - - return iIgnore; -} - -//========================================================= -// IRelationship - overridden for bullsquid so that it can -// be made to ignore its love of headcrabs for a while. -//========================================================= -int CBullsquid::IRelationship ( CBaseEntity *pTarget ) -{ - if ( gpGlobals->time - m_flLastHurtTime < 5 && FClassnameIs ( pTarget->pev, "monster_headcrab" ) ) - { - // if squid has been hurt in the last 5 seconds, and is getting relationship for a headcrab, - // tell squid to disregard crab. - return R_NO; - } - - return CBaseMonster :: IRelationship ( pTarget ); -} - -//========================================================= -// TakeDamage - overridden for bullsquid so we can keep track -// of how much time has passed since it was last injured -//========================================================= -int CBullsquid :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flDist; - Vector vecApex; - - // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, - // it will swerve. (whew). - if ( m_hEnemy != 0 && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3 ) - { - flDist = ( pev->origin - m_hEnemy->pev->origin ).Length2D(); - - if ( flDist > SQUID_SPRINT_DIST ) - { - flDist = ( pev->origin - m_Route[ m_iRouteIndex ].vecLocation ).Length2D();// reusing flDist. - - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist * 0.5, m_hEnemy, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR | bits_MF_DONT_SIMPLIFY ); - } - } - } - - if ( !FClassnameIs ( pevAttacker, "monster_headcrab" ) ) - { - // don't forget about headcrabs if it was a headcrab that hurt the squid. - m_flLastHurtTime = gpGlobals->time; - } - - return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBullsquid :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( IsMoving() && flDist >= 512 ) - { - // squid will far too far behind if he stops running to spit at this distance from the enemy. - return FALSE; - } - - if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime ) - { - if ( m_hEnemy != 0 ) - { - if ( fabs( pev->origin.z - m_hEnemy->pev->origin.z ) > 256 ) - { - // don't try to spit at someone up really high or down really low. - return FALSE; - } - } - - if ( IsMoving() ) - { - // don't spit again for a long time, resume chasing enemy. - m_flNextSpitTime = gpGlobals->time + 5; - } - else - { - // not moving, so spit again pretty soon. - m_flNextSpitTime = gpGlobals->time + 0.5; - } - - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the tailwhip attack -//========================================================= -BOOL CBullsquid :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( m_hEnemy->pev->health <= gSkillData.bullsquidDmgWhip && flDist <= 85 && flDot >= 0.7 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 - bullsquid is a big guy, so has a longer -// melee range than most monsters. This is the bite attack. -// this attack will not be performed if the tailwhip attack -// is valid. -//========================================================= -BOOL CBullsquid :: CheckMeleeAttack2 ( float flDot, float flDist ) -{ - if ( flDist <= 85 && flDot >= 0.7 && !HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) // The player & bullsquid can be as much as their bboxes - { // apart (48 * sqrt(3)) and he can still attack (85 is a little more than 48*sqrt(3)) - return TRUE; - } - return FALSE; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CBullsquid :: FValidateHintType ( short sHint ) -{ - size_t i; - - static short sSquidHints[] = - { - HINT_WORLD_HUMAN_BLOOD, - }; - - for ( i = 0 ; i < ARRAYSIZE ( sSquidHints ) ; i++ ) - { - if ( sSquidHints[ i ] == sHint ) - { - return TRUE; - } - } - - ALERT ( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CBullsquid :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_CARCASS | - bits_SOUND_MEAT | - bits_SOUND_GARBAGE | - bits_SOUND_PLAYER; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CBullsquid :: Classify ( void ) -{ - return CLASS_ALIEN_PREDATOR; -} - -//========================================================= -// IdleSound -//========================================================= -#define SQUID_ATTN_IDLE (float)1.5 -void CBullsquid :: IdleSound ( void ) -{ - switch ( RANDOM_LONG(0,4) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, SQUID_ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, SQUID_ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle3.wav", 1, SQUID_ATTN_IDLE ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle4.wav", 1, SQUID_ATTN_IDLE ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle5.wav", 1, SQUID_ATTN_IDLE ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CBullsquid :: PainSound ( void ) -{ - int iPitch = RANDOM_LONG( 85, 120 ); - - switch ( RANDOM_LONG(0,3) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 2: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 3: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_pain4.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CBullsquid :: AlertSound ( void ) -{ - int iPitch = RANDOM_LONG( 140, 160 ); - - switch ( RANDOM_LONG ( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle1.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "bullchicken/bc_idle2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CBullsquid :: SetYawSpeed ( void ) -{ - int ys; - - ys = 0; - - switch ( m_Activity ) - { - case ACT_WALK: ys = 90; break; - case ACT_RUN: ys = 90; break; - case ACT_IDLE: ys = 90; break; - case ACT_RANGE_ATTACK1: ys = 90; break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CBullsquid :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case BSQUID_AE_SPIT: - { - Vector vecSpitOffset; - Vector vecSpitDir; - - UTIL_MakeVectors ( pev->angles ); - - // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. - // we should be able to read the position of bones at runtime for this info. - vecSpitOffset = ( gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23 ); - vecSpitOffset = ( pev->origin + vecSpitOffset ); - vecSpitDir = ( ( m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs ) - vecSpitOffset ).Normalize(); - - vecSpitDir.x += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.y += RANDOM_FLOAT( -0.05, 0.05 ); - vecSpitDir.z += RANDOM_FLOAT( -0.05, 0 ); - - - // do stuff for this event. - AttackSound(); - - // spew the spittle temporary ents. - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); - WRITE_BYTE( TE_SPRITE_SPRAY ); - WRITE_COORD( vecSpitOffset.x); // pos - WRITE_COORD( vecSpitOffset.y); - WRITE_COORD( vecSpitOffset.z); - WRITE_COORD( vecSpitDir.x); // dir - WRITE_COORD( vecSpitDir.y); - WRITE_COORD( vecSpitDir.z); - WRITE_SHORT( iSquidSpitSprite ); // model - WRITE_BYTE ( 15 ); // count - WRITE_BYTE ( 210 ); // speed - WRITE_BYTE ( 25 ); // noise ( client will divide by 100 ) - MESSAGE_END(); - - CSquidSpit::Shoot( pev, vecSpitOffset, vecSpitDir * 900 ); - } - break; - - case BSQUID_AE_BITE: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgBite, DMG_SLASH ); - - if ( pHurt ) - { - //pHurt->pev->punchangle.z = -15; - //pHurt->pev->punchangle.x = -45; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - - case BSQUID_AE_TAILWHIP: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.bullsquidDmgWhip, DMG_CLUB | DMG_ALWAYSGIB ); - if ( pHurt ) - { - pHurt->pev->punchangle.z = -20; - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 200; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 100; - } - } - break; - - case BSQUID_AE_BLINK: - { - // close eye. - pev->skin = 1; - } - break; - - case BSQUID_AE_HOP: - { - float flGravity = g_psv_gravity->value; - - // throw the squid up into the air on this frame. - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - pev->flags -= FL_ONGROUND; - } - - // jump into air for 0.8 (24/30) seconds -// pev->velocity.z += (0.875 * flGravity) * 0.5; - pev->velocity.z += (0.625 * flGravity) * 0.5; - } - break; - - case BSQUID_AE_THROW: - { - int iPitch; - - // squid throws its prey IF the prey is a client. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, 0, 0 ); - - - if ( pHurt ) - { - // croonchy bite sound - iPitch = RANDOM_FLOAT( 90, 110 ); - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite2.wav", 1, ATTN_NORM, 0, iPitch ); - break; - case 1: - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "bullchicken/bc_bite3.wav", 1, ATTN_NORM, 0, iPitch ); - break; - } - - - //pHurt->pev->punchangle.x = RANDOM_LONG(0,34) - 5; - //pHurt->pev->punchangle.z = RANDOM_LONG(0,49) - 25; - //pHurt->pev->punchangle.y = RANDOM_LONG(0,89) - 45; - - // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. - UTIL_ScreenShake( pHurt->pev->origin, 25.0, 1.5, 0.7, 2 ); - - if ( pHurt->IsPlayer() ) - { - UTIL_MakeVectors( pev->angles ); - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 300 + gpGlobals->v_up * 300; - } - } - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CBullsquid :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/bullsquid.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.bullsquidHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - m_fCanThreatDisplay = TRUE; - m_flNextSpitTime = gpGlobals->time; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CBullsquid :: Precache() -{ - PRECACHE_MODEL("models/bullsquid.mdl"); - - PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile. - - iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event - - PRECACHE_SOUND("bullchicken/bc_attack2.wav"); - PRECACHE_SOUND("bullchicken/bc_attack3.wav"); - - PRECACHE_SOUND("bullchicken/bc_die1.wav"); - PRECACHE_SOUND("bullchicken/bc_die2.wav"); - PRECACHE_SOUND("bullchicken/bc_die3.wav"); - - PRECACHE_SOUND("bullchicken/bc_idle1.wav"); - PRECACHE_SOUND("bullchicken/bc_idle2.wav"); - PRECACHE_SOUND("bullchicken/bc_idle3.wav"); - PRECACHE_SOUND("bullchicken/bc_idle4.wav"); - PRECACHE_SOUND("bullchicken/bc_idle5.wav"); - - PRECACHE_SOUND("bullchicken/bc_pain1.wav"); - PRECACHE_SOUND("bullchicken/bc_pain2.wav"); - PRECACHE_SOUND("bullchicken/bc_pain3.wav"); - PRECACHE_SOUND("bullchicken/bc_pain4.wav"); - - PRECACHE_SOUND("bullchicken/bc_attackgrowl.wav"); - PRECACHE_SOUND("bullchicken/bc_attackgrowl2.wav"); - PRECACHE_SOUND("bullchicken/bc_attackgrowl3.wav"); - - PRECACHE_SOUND("bullchicken/bc_acid1.wav"); - - PRECACHE_SOUND("bullchicken/bc_bite2.wav"); - PRECACHE_SOUND("bullchicken/bc_bite3.wav"); - - PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); - PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); - -} - -//========================================================= -// DeathSound -//========================================================= -void CBullsquid :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AttackSound -//========================================================= -void CBullsquid :: AttackSound ( void ) -{ - switch ( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack2.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "bullchicken/bc_attack3.wav", 1, ATTN_NORM ); - break; - } -} - - -//======================================================== -// RunAI - overridden for bullsquid because there are things -// that need to be checked every think. -//======================================================== -void CBullsquid :: RunAI ( void ) -{ - // first, do base class stuff - CBaseMonster :: RunAI(); - - if ( pev->skin != 0 ) - { - // close eye if it was open. - pev->skin = 0; - } - - if ( RANDOM_LONG(0,39) == 0 ) - { - pev->skin = 1; - } - - if ( m_hEnemy != 0 && m_Activity == ACT_RUN ) - { - // chasing enemy. Sprint for last bit - if ( (pev->origin - m_hEnemy->pev->origin).Length2D() < SQUID_SPRINT_DIST ) - { - pev->framerate = 1.25; - } - } - -} - -//======================================================== -// AI Schedules Specific to this monster -//========================================================= - -// primary range attack -Task_t tlSquidRangeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSquidRangeAttack1[] = -{ - { - tlSquidRangeAttack1, - ARRAYSIZE ( tlSquidRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "Squid Range Attack1" - }, -}; - -// Chase enemy schedule -Task_t tlSquidChaseEnemy1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 },// !!!OEM - this will stop nasty squid oscillation. - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slSquidChaseEnemy[] = -{ - { - tlSquidChaseEnemy1, - ARRAYSIZE ( tlSquidChaseEnemy1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_SMELL_FOOD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_TASK_FAILED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_MEAT, - "Squid Chase Enemy" - }, -}; - -Task_t tlSquidHurtHop[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_SQUID_HOPTURN, (float)0 }, - { TASK_FACE_ENEMY, (float)0 },// in case squid didn't turn all the way in the air. -}; - -Schedule_t slSquidHurtHop[] = -{ - { - tlSquidHurtHop, - ARRAYSIZE ( tlSquidHurtHop ), - 0, - 0, - "SquidHurtHop" - } -}; - -Task_t tlSquidSeeCrab[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EXCITED }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slSquidSeeCrab[] = -{ - { - tlSquidSeeCrab, - ARRAYSIZE ( tlSquidSeeCrab ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "SquidSeeCrab" - } -}; - -// squid walks to something tasty and eats it. -Task_t tlSquidEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidEat[] = -{ - { - tlSquidEat, - ARRAYSIZE( tlSquidEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidEat" - } -}; - -// this is a bit different than just Eat. We use this schedule when the food is far away, occluded, or behind -// the squid. This schedule plays a sniff animation before going to the source of food. -Task_t tlSquidSniffAndEat[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the food - { TASK_PLAY_SEQUENCE, (float)ACT_DETECT_SCENT }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_PLAY_SEQUENCE, (float)ACT_EAT }, - { TASK_EAT, (float)50 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidSniffAndEat[] = -{ - { - tlSquidSniffAndEat, - ARRAYSIZE( tlSquidSniffAndEat ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_MEAT | - bits_SOUND_CARCASS, - "SquidSniffAndEat" - } -}; - -// squid does this to stinky things. -Task_t tlSquidWallow[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_EAT, (float)10 },// this is in case the squid can't get to the stinkiness - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSCENT, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_INSPECT_FLOOR}, - { TASK_EAT, (float)50 },// keeps squid from eating or sniffing anything else for a while. - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSquidWallow[] = -{ - { - tlSquidWallow, - ARRAYSIZE( tlSquidWallow ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY , - - // even though HEAR_SOUND/SMELL FOOD doesn't break this schedule, we need this mask - // here or the monster won't detect these sounds at ALL while running this schedule. - bits_SOUND_GARBAGE, - - "SquidWallow" - } -}; - -DEFINE_CUSTOM_SCHEDULES( CBullsquid ) -{ - slSquidRangeAttack1, - slSquidChaseEnemy, - slSquidHurtHop, - slSquidSeeCrab, - slSquidEat, - slSquidSniffAndEat, - slSquidWallow -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CBullsquid, CBaseMonster ); - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CBullsquid :: GetSchedule( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - { - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - return GetScheduleOfType ( SCHED_SQUID_HURTHOP ); - } - - if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if ( HasConditions(bits_COND_SMELL) ) - { - // there's something stinky. - CSound *pSound; - - pSound = PBestScent(); - if ( pSound ) - return GetScheduleOfType( SCHED_SQUID_WALLOW); - } - - break; - } - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - if ( m_fCanThreatDisplay && IRelationship( m_hEnemy ) == R_HT ) - { - // this means squid sees a headcrab! - m_fCanThreatDisplay = FALSE;// only do the headcrab dance once per lifetime. - return GetScheduleOfType ( SCHED_SQUID_SEECRAB ); - } - else - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - } - - if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = PBestScent(); - - if ( pSound && (!FInViewCone ( &pSound->m_vecOrigin ) || !FVisible ( pSound->m_vecOrigin )) ) - { - // scent is behind or occluded - return GetScheduleOfType( SCHED_SQUID_SNIFF_AND_EAT ); - } - - // food is right out in the open. Just go get it. - return GetScheduleOfType( SCHED_SQUID_EAT ); - } - - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK2 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK2 ); - } - - return GetScheduleOfType ( SCHED_CHASE_ENEMY ); - - break; - } - default: - break; - } - - return CBaseMonster :: GetSchedule(); -} - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t* CBullsquid :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_RANGE_ATTACK1: - return &slSquidRangeAttack1[ 0 ]; - break; - case SCHED_SQUID_HURTHOP: - return &slSquidHurtHop[ 0 ]; - break; - case SCHED_SQUID_SEECRAB: - return &slSquidSeeCrab[ 0 ]; - break; - case SCHED_SQUID_EAT: - return &slSquidEat[ 0 ]; - break; - case SCHED_SQUID_SNIFF_AND_EAT: - return &slSquidSniffAndEat[ 0 ]; - break; - case SCHED_SQUID_WALLOW: - return &slSquidWallow[ 0 ]; - break; - case SCHED_CHASE_ENEMY: - return &slSquidChaseEnemy[ 0 ]; - break; - } - - return CBaseMonster :: GetScheduleOfType ( Type ); -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. OVERRIDDEN for bullsquid because it needs to -// know explicitly when the last attempt to chase the enemy -// failed, since that impacts its attack choices. -//========================================================= -void CBullsquid :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_MELEE_ATTACK2: - { - switch ( RANDOM_LONG ( 0, 2 ) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "bullchicken/bc_attackgrowl3.wav", 1, ATTN_NORM ); - break; - } - - CBaseMonster :: StartTask ( pTask ); - break; - } - case TASK_SQUID_HOPTURN: - { - SetActivity ( ACT_HOP ); - MakeIdealYaw ( m_vecEnemyLKP ); - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - if ( BuildRoute ( m_hEnemy->pev->origin, bits_MF_TO_ENEMY, m_hEnemy ) ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - { - CBaseMonster :: StartTask ( pTask ); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CBullsquid :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_SQUID_HOPTURN: - { - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CBaseMonster :: RunTask( pTask ); - break; - } - } -} - - -//========================================================= -// GetIdealState - Overridden for Bullsquid to deal with -// the feature that makes it lose interest in headcrabs for -// a while if something injures it. -//========================================================= -MONSTERSTATE CBullsquid :: GetIdealState ( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - /* - COMBAT goes to ALERT upon death of enemy - */ - { - if ( m_hEnemy != 0 && ( iConditions & bits_COND_LIGHT_DAMAGE || iConditions & bits_COND_HEAVY_DAMAGE ) && FClassnameIs( m_hEnemy->pev, "monster_headcrab" ) ) - { - // if the squid has a headcrab enemy and something hurts it, it's going to forget about the crab for a while. - m_hEnemy = 0; - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - break; - } - default: - break; - } - - m_IdealMonsterState = CBaseMonster :: GetIdealState(); - - return m_IdealMonsterState; -} - diff --git a/sdk/dlls/buttons.cpp b/sdk/dlls/buttons.cpp deleted file mode 100644 index f7734b6..0000000 --- a/sdk/dlls/buttons.cpp +++ /dev/null @@ -1,1284 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== buttons.cpp ======================================================== - - button-related code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "doors.h" - -#if !defined ( _WIN32 ) -#include // memset()))) -#endif - -#define SF_BUTTON_DONTMOVE 1 -#define SF_ROTBUTTON_NOTSOLID 1 -#define SF_BUTTON_TOGGLE 32 // button stays pushed until reactivated -#define SF_BUTTON_SPARK_IF_OFF 64 // button sparks in OFF state -#define SF_BUTTON_TOUCH_ONLY 256 // button only fires as a result of USE key. - -#define SF_GLOBAL_SET 1 // Set global state to initial state on spawn - -class CEnvGlobal : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_globalstate; - int m_triggermode; - int m_initialstate; -}; - -TYPEDESCRIPTION CEnvGlobal::m_SaveData[] = -{ - DEFINE_FIELD( CEnvGlobal, m_globalstate, FIELD_STRING ), - DEFINE_FIELD( CEnvGlobal, m_triggermode, FIELD_INTEGER ), - DEFINE_FIELD( CEnvGlobal, m_initialstate, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CEnvGlobal, CBaseEntity ); - -LINK_ENTITY_TO_CLASS( env_global, CEnvGlobal ); - -void CEnvGlobal::KeyValue( KeyValueData *pkvd ) -{ - pkvd->fHandled = TRUE; - - if ( FStrEq(pkvd->szKeyName, "globalstate") ) // State name - m_globalstate = ALLOC_STRING( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "triggermode") ) - m_triggermode = atoi( pkvd->szValue ); - else if ( FStrEq(pkvd->szKeyName, "initialstate") ) - m_initialstate = atoi( pkvd->szValue ); - else - CPointEntity::KeyValue( pkvd ); -} - -void CEnvGlobal::Spawn( void ) -{ - if ( !m_globalstate ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - if ( FBitSet( pev->spawnflags, SF_GLOBAL_SET ) ) - { - if ( !gGlobalState.EntityInTable( m_globalstate ) ) - gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, (GLOBALESTATE)m_initialstate ); - } -} - - -void CEnvGlobal::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - GLOBALESTATE oldState = gGlobalState.EntityGetState( m_globalstate ); - GLOBALESTATE newState; - - switch( m_triggermode ) - { - case 0: - newState = GLOBAL_OFF; - break; - - case 1: - newState = GLOBAL_ON; - break; - - case 2: - newState = GLOBAL_DEAD; - break; - - default: - case 3: - if ( oldState == GLOBAL_ON ) - newState = GLOBAL_OFF; - else if ( oldState == GLOBAL_OFF ) - newState = GLOBAL_ON; - else - newState = oldState; - } - - if ( gGlobalState.EntityInTable( m_globalstate ) ) - gGlobalState.EntitySetState( m_globalstate, newState ); - else - gGlobalState.EntityAdd( m_globalstate, gpGlobals->mapname, newState ); -} - - - -TYPEDESCRIPTION CMultiSource::m_SaveData[] = -{ - //!!!BUGBUG FIX - DEFINE_ARRAY( CMultiSource, m_rgEntities, FIELD_EHANDLE, MS_MAX_TARGETS ), - DEFINE_ARRAY( CMultiSource, m_rgTriggered, FIELD_INTEGER, MS_MAX_TARGETS ), - DEFINE_FIELD( CMultiSource, m_iTotal, FIELD_INTEGER ), - DEFINE_FIELD( CMultiSource, m_globalstate, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CMultiSource, CBaseEntity ); - -LINK_ENTITY_TO_CLASS( multisource, CMultiSource ); -// -// Cache user-entity-field values until spawn is called. -// - -void CMultiSource::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "killtarget") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else if ( FStrEq(pkvd->szKeyName, "globalstate") ) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -#define SF_MULTI_INIT 1 - -void CMultiSource::Spawn() -{ - // set up think for later registration - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time + 0.1; - pev->spawnflags |= SF_MULTI_INIT; // Until it's initialized - SetThink(&CMultiSource::Register); -} - -void CMultiSource::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int i = 0; - - // Find the entity in our list - while (i < m_iTotal) - if ( m_rgEntities[i++] == pCaller ) - break; - - // if we didn't find it, report error and leave - if (i > m_iTotal) - { - ALERT(at_console, "MultiSrc:Used by non member %s.\n", STRING(pCaller->pev->classname)); - return; - } - - // CONSIDER: a Use input to the multisource always toggles. Could check useType for ON/OFF/TOGGLE - - m_rgTriggered[i-1] ^= 1; - - // - if ( IsTriggered( pActivator ) ) - { - ALERT( at_aiconsole, "Multisource %s enabled (%d inputs)\n", STRING(pev->targetname), m_iTotal ); - USE_TYPE useType = USE_TOGGLE; - if ( m_globalstate ) - useType = USE_ON; - SUB_UseTargets( NULL, useType, 0 ); - } -} - - -BOOL CMultiSource::IsTriggered( CBaseEntity * ) -{ - // Is everything triggered? - int i = 0; - - // Still initializing? - if ( pev->spawnflags & SF_MULTI_INIT ) - return 0; - - while (i < m_iTotal) - { - if (m_rgTriggered[i] == 0) - break; - i++; - } - - if (i == m_iTotal) - { - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - return 1; - } - - return 0; -} - -void CMultiSource::Register(void) -{ - edict_t *pentTarget = NULL; - - m_iTotal = 0; - memset( m_rgEntities, 0, MS_MAX_TARGETS * sizeof(EHANDLE) ); - - SetThink(&CMultiSource::SUB_DoNothing); - - // search for all entities which target this multisource (pev->targetname) - - pentTarget = FIND_ENTITY_BY_STRING(NULL, "target", STRING(pev->targetname)); - - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) - { - CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); - if ( pTarget ) - m_rgEntities[m_iTotal++] = pTarget; - - pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "target", STRING(pev->targetname)); - } - - pentTarget = FIND_ENTITY_BY_STRING(NULL, "classname", "multi_manager"); - while (!FNullEnt(pentTarget) && (m_iTotal < MS_MAX_TARGETS)) - { - CBaseEntity *pTarget = CBaseEntity::Instance(pentTarget); - if ( pTarget && pTarget->HasTarget(pev->targetname) ) - m_rgEntities[m_iTotal++] = pTarget; - - pentTarget = FIND_ENTITY_BY_STRING( pentTarget, "classname", "multi_manager" ); - } - - pev->spawnflags &= ~SF_MULTI_INIT; -} - -// CBaseButton -TYPEDESCRIPTION CBaseButton::m_SaveData[] = -{ - DEFINE_FIELD( CBaseButton, m_fStayPushed, FIELD_BOOLEAN ), - DEFINE_FIELD( CBaseButton, m_fRotating, FIELD_BOOLEAN ), - - DEFINE_FIELD( CBaseButton, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CBaseButton, m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_bUnlockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseButton, m_strChangeTarget, FIELD_STRING ), -// DEFINE_FIELD( CBaseButton, m_ls, FIELD_??? ), // This is restored in Precache() -}; - - -IMPLEMENT_SAVERESTORE( CBaseButton, CBaseToggle ); - -void CBaseButton::Precache( void ) -{ - const char *pszSound; - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state - { - PRECACHE_SOUND ("buttons/spark1.wav"); - PRECACHE_SOUND ("buttons/spark2.wav"); - PRECACHE_SOUND ("buttons/spark3.wav"); - PRECACHE_SOUND ("buttons/spark4.wav"); - PRECACHE_SOUND ("buttons/spark5.wav"); - PRECACHE_SOUND ("buttons/spark6.wav"); - } - - // get door button sounds, for doors which require buttons to open - - if (m_bLockedSound) - { - pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); - } - - if (m_bUnlockedSound) - { - pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = MAKE_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = MAKE_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = MAKE_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = MAKE_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = MAKE_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = MAKE_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = MAKE_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = MAKE_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = MAKE_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = 0; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = MAKE_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = MAKE_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = MAKE_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = MAKE_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = MAKE_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = MAKE_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = MAKE_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = MAKE_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = 0; break; - } -} - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseButton::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "changetarget")) - { - m_strChangeTarget = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -// -// ButtonShot -// -int CBaseButton::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return 0; - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - m_hActivator = CBaseEntity::Instance( pevAttacker ); - if ( m_hActivator == 0 ) - return 0; - - if ( code == BUTTON_RETURN ) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - // Toggle buttons fire when they get back to their "home" position - if ( !(pev->spawnflags & SF_BUTTON_TOGGLE) ) - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - ButtonReturn(); - } - else // code == BUTTON_ACTIVATE - ButtonActivate( ); - - return 0; -} - -/*QUAKED func_button (0 .5 .8) ? -When a button is touched, it moves some distance in the direction of it's angle, -triggers all of it's targets, waits some time, then returns to it's original position -where it can be triggered again. - -"angle" determines the opening direction -"target" all entities with a matching targetname will be used -"speed" override the default 40 speed -"wait" override the default 1 second wait (-1 = never return) -"lip" override the default 4 pixel lip remaining at end of move -"health" if set, the button must be killed instead of touched -"sounds" -0) steam metal -1) wooden clunk -2) metallic click -3) in-out -*/ -LINK_ENTITY_TO_CLASS( func_button, CBaseButton ); - - -void CBaseButton::Spawn( ) -{ - const char *pszSound; - - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - - Precache(); - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) )// this button should spark in OFF state - { - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + 0.5;// no hurry, make sure everything else spawns - } - - SetMovedir(pev); - - pev->movetype = MOVETYPE_PUSH; - pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); - - if (pev->speed == 0) - pev->speed = 40; - - if (pev->health > 0) - { - pev->takedamage = DAMAGE_YES; - } - - if (m_flWait == 0) - m_flWait = 1; - if (m_flLip == 0) - m_flLip = 4; - - m_toggle_state = TS_AT_BOTTOM; - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - - - // Is this a non-moving button? - if ( ((m_vecPosition2 - m_vecPosition1).Length() < 1) || (pev->spawnflags & SF_BUTTON_DONTMOVE) ) - m_vecPosition2 = m_vecPosition1; - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = FALSE; - - // if the button is flagged for USE button activation only, take away it's touch function and add a use function - - if ( FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // touchable button - { - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - SetTouch ( NULL ); - SetUse ( &CBaseButton::ButtonUse ); - } -} - - -// Button sound table. -// Also used by CBaseDoor to get 'touched' door lock/unlock sounds - -const char *ButtonSound( int sound ) -{ - const char *pszSound; - - switch ( sound ) - { - case 0: pszSound = "common/null.wav"; break; - case 1: pszSound = "buttons/button1.wav"; break; - case 2: pszSound = "buttons/button2.wav"; break; - case 3: pszSound = "buttons/button3.wav"; break; - case 4: pszSound = "buttons/button4.wav"; break; - case 5: pszSound = "buttons/button5.wav"; break; - case 6: pszSound = "buttons/button6.wav"; break; - case 7: pszSound = "buttons/button7.wav"; break; - case 8: pszSound = "buttons/button8.wav"; break; - case 9: pszSound = "buttons/button9.wav"; break; - case 10: pszSound = "buttons/button10.wav"; break; - case 11: pszSound = "buttons/button11.wav"; break; - case 12: pszSound = "buttons/latchlocked1.wav"; break; - case 13: pszSound = "buttons/latchunlocked1.wav"; break; - case 14: pszSound = "buttons/lightswitch2.wav";break; - -// next 6 slots reserved for any additional sliding button sounds we may add - - case 21: pszSound = "buttons/lever1.wav"; break; - case 22: pszSound = "buttons/lever2.wav"; break; - case 23: pszSound = "buttons/lever3.wav"; break; - case 24: pszSound = "buttons/lever4.wav"; break; - case 25: pszSound = "buttons/lever5.wav"; break; - - default:pszSound = "buttons/button9.wav"; break; - } - - return pszSound; -} - -// -// Makes flagged buttons spark when turned off -// - -void DoSpark(entvars_t *pev, const Vector &location ) -{ - Vector tmp = location + pev->size * 0.5; - UTIL_Sparks( tmp ); - - float flVolume = RANDOM_FLOAT ( 0.25 , 0.75 ) * 0.4;//random volume range - switch ( (int)(RANDOM_FLOAT(0,1) * 6) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark1.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark2.wav", flVolume, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark3.wav", flVolume, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark4.wav", flVolume, ATTN_NORM); break; - case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - case 5: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } -} - -void CBaseButton::ButtonSpark ( void ) -{ - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) );// spark again at random interval - - DoSpark( pev, pev->mins ); -} - - -// -// Button's Use function -// -void CBaseButton::ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - // UNDONE: Should this use ButtonResponseToTouch() too? - if (m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN ) - return; - - m_hActivator = pActivator; - if ( m_toggle_state == TS_AT_TOP) - { - if (!m_fStayPushed && FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE)) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - //SUB_UseTargets( m_eoActivator ); - ButtonReturn(); - } - } - else - ButtonActivate( ); -} - - -CBaseButton::BUTTON_CODE CBaseButton::ButtonResponseToTouch( void ) -{ - // Ignore touches if button is moving, or pushed-in and waiting to auto-come-out. - if (m_toggle_state == TS_GOING_UP || - m_toggle_state == TS_GOING_DOWN || - (m_toggle_state == TS_AT_TOP && !m_fStayPushed && !FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) ) - return BUTTON_NOTHING; - - if (m_toggle_state == TS_AT_TOP) - { - if((FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) && !m_fStayPushed) - { - return BUTTON_RETURN; - } - } - else - return BUTTON_ACTIVATE; - - return BUTTON_NOTHING; -} - - -// -// Touching a button simply "activates" it. -// -void CBaseButton:: ButtonTouch( CBaseEntity *pOther ) -{ - // Ignore touches by anything but players - if (!FClassnameIs(pOther->pev, "player")) - return; - - m_hActivator = pOther; - - BUTTON_CODE code = ButtonResponseToTouch(); - - if ( code == BUTTON_NOTHING ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) - { - // play button locked sound - PlayLockSounds(pev, &m_ls, TRUE, TRUE); - return; - } - - // Temporarily disable the touch function, until movement is finished. - SetTouch( NULL ); - - if ( code == BUTTON_RETURN ) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - ButtonReturn(); - } - else // code == BUTTON_ACTIVATE - ButtonActivate( ); -} - -// -// Starts the button moving "in/up". -// -void CBaseButton::ButtonActivate( ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - { - // button is locked, play locked sound - PlayLockSounds(pev, &m_ls, TRUE, TRUE); - return; - } - else - { - // button is unlocked, play unlocked sound - PlayLockSounds(pev, &m_ls, FALSE, TRUE); - } - - ASSERT(m_toggle_state == TS_AT_BOTTOM); - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseButton::TriggerAndWait ); - if (!m_fRotating) - LinearMove( m_vecPosition2, pev->speed); - else - AngularMove( m_vecAngle2, pev->speed); -} - -// -// Button has reached the "in/up" position. Activate its "targets", and pause before "popping out". -// -void CBaseButton::TriggerAndWait( void ) -{ - ASSERT(m_toggle_state == TS_GOING_UP); - - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return; - - m_toggle_state = TS_AT_TOP; - - // If button automatically comes back out, start it moving out. - // Else re-instate touch method - if (m_fStayPushed || FBitSet ( pev->spawnflags, SF_BUTTON_TOGGLE ) ) - { - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! - { - // ALL buttons are now use only - SetTouch ( NULL ); - } - else - SetTouch( &CBaseButton::ButtonTouch ); - } - else - { - pev->nextthink = pev->ltime + m_flWait; - SetThink( &CBaseButton::ButtonReturn ); - } - - pev->frame = 1; // use alternate textures - - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); -} - - -// -// Starts the button moving "out/down". -// -void CBaseButton::ButtonReturn( void ) -{ - ASSERT(m_toggle_state == TS_AT_TOP); - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseButton::ButtonBackHome ); - if (!m_fRotating) - LinearMove( m_vecPosition1, pev->speed); - else - AngularMove( m_vecAngle1, pev->speed); - - pev->frame = 0; // use normal textures -} - - -// -// Button has returned to start state. Quiesce it. -// -void CBaseButton::ButtonBackHome( void ) -{ - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; - - if ( FBitSet(pev->spawnflags, SF_BUTTON_TOGGLE) ) - { - //EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - } - - - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - - if (FNullEnt(pentTarget)) - break; - - if (!FClassnameIs(pentTarget, "multisource")) - continue; - CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); - - if ( pTarget ) - pTarget->Use( m_hActivator, this, USE_TOGGLE, 0 ); - } - } - -// Re-instate touch method, movement cycle is complete. - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) // this button only works if USED, not touched! - { - // All buttons are now use only - SetTouch ( NULL ); - } - else - SetTouch( &CBaseButton::ButtonTouch ); - -// reset think for a sparking button - if ( FBitSet ( pev->spawnflags, SF_BUTTON_SPARK_IF_OFF ) ) - { - SetThink ( &CBaseButton::ButtonSpark ); - pev->nextthink = gpGlobals->time + 0.5;// no hurry. - } -} - - - -// -// Rotating button (aka "lever") -// -class CRotButton : public CBaseButton -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( func_rot_button, CRotButton ); - -void CRotButton::Spawn( void ) -{ - const char *pszSound; - //---------------------------------------------------- - //determine sounds for buttons - //a sound of 0 should not make a sound - //---------------------------------------------------- - pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - - // set the axis of rotation - CBaseToggle::AxisDir( pev ); - - // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - pev->movetype = MOVETYPE_PUSH; - - if ( pev->spawnflags & SF_ROTBUTTON_NOTSOLID ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - SET_MODEL(ENT(pev), STRING(pev->model)); - - if (pev->speed == 0) - pev->speed = 40; - - if (m_flWait == 0) - m_flWait = 1; - - if (pev->health > 0) - { - pev->takedamage = DAMAGE_YES; - } - - m_toggle_state = TS_AT_BOTTOM; - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating button start/end positions are equal"); - - m_fStayPushed = (m_flWait == -1 ? TRUE : FALSE); - m_fRotating = TRUE; - - // if the button is flagged for USE button activation only, take away it's touch function and add a use function - if ( !FBitSet ( pev->spawnflags, SF_BUTTON_TOUCH_ONLY ) ) - { - SetTouch ( NULL ); - SetUse ( &CRotButton::ButtonUse ); - } - else // touchable button - SetTouch( &CRotButton::ButtonTouch ); - - //SetTouch( ButtonTouch ); -} - - -// Make this button behave like a door (HACKHACK) -// This will disable use and make the button solid -// rotating buttons were made SOLID_NOT by default since their were some -// collision problems with them... -#define SF_MOMENTARY_DOOR 0x0001 - -class CMomentaryRotButton : public CBaseToggle -{ -public: - void Spawn ( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) - { - int flags = CBaseToggle :: ObjectCaps() & (~FCAP_ACROSS_TRANSITION); - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) - return flags; - return flags | FCAP_CONTINUOUS_USE; - } - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Off( void ); - void EXPORT Return( void ); - void UpdateSelf( float value ); - void UpdateSelfReturn( float value ); - void UpdateAllButtons( float value, int start ); - - void PlaySound( void ); - void UpdateTarget( float value ); - - static CMomentaryRotButton *Instance( edict_t *pent ) { return (CMomentaryRotButton *)GET_PRIVATE(pent);}; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_lastUsed; - int m_direction; - float m_returnSpeed; - vec3_t m_start; - vec3_t m_end; - int m_sounds; -}; -TYPEDESCRIPTION CMomentaryRotButton::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryRotButton, m_lastUsed, FIELD_INTEGER ), - DEFINE_FIELD( CMomentaryRotButton, m_direction, FIELD_INTEGER ), - DEFINE_FIELD( CMomentaryRotButton, m_returnSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CMomentaryRotButton, m_start, FIELD_VECTOR ), - DEFINE_FIELD( CMomentaryRotButton, m_end, FIELD_VECTOR ), - DEFINE_FIELD( CMomentaryRotButton, m_sounds, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CMomentaryRotButton, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( momentary_rot_button, CMomentaryRotButton ); - -void CMomentaryRotButton::Spawn( void ) -{ - CBaseToggle::AxisDir( pev ); - - if ( pev->speed == 0 ) - pev->speed = 100; - - if ( m_flMoveDistance < 0 ) - { - m_start = pev->angles + pev->movedir * m_flMoveDistance; - m_end = pev->angles; - m_direction = 1; // This will toggle to -1 on the first use() - m_flMoveDistance = -m_flMoveDistance; - } - else - { - m_start = pev->angles; - m_end = pev->angles + pev->movedir * m_flMoveDistance; - m_direction = -1; // This will toggle to +1 on the first use() - } - - if ( pev->spawnflags & SF_MOMENTARY_DOOR ) - pev->solid = SOLID_BSP; - else - pev->solid = SOLID_NOT; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - const char *pszSound = ButtonSound( m_sounds ); - PRECACHE_SOUND(pszSound); - pev->noise = ALLOC_STRING(pszSound); - m_lastUsed = 0; -} - -void CMomentaryRotButton::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "returnspeed")) - { - m_returnSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CMomentaryRotButton::PlaySound( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); -} - -// BUGBUG: This design causes a latentcy. When the button is retriggered, the first impulse -// will send the target in the wrong direction because the parameter is calculated based on the -// current, not future position. -void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; - - UpdateAllButtons( pev->ideal_yaw, 1 ); - - // Calculate destination angle and use it to predict value, this prevents sending target in wrong direction on retriggering - Vector dest = pev->angles + pev->avelocity * (pev->nextthink - pev->ltime); - float value1 = CBaseToggle::AxisDelta( pev->spawnflags, dest, m_start ) / m_flMoveDistance; - UpdateTarget( value1 ); - -} - -void CMomentaryRotButton::UpdateAllButtons( float value, int start ) -{ - // Update all rot buttons attached to the same target - edict_t *pentTarget = NULL; - for (;;) - { - - pentTarget = FIND_ENTITY_BY_STRING(pentTarget, "target", STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs( VARS(pentTarget), "momentary_rot_button" ) ) - { - CMomentaryRotButton *pEntity = CMomentaryRotButton::Instance(pentTarget); - if ( pEntity ) - { - if ( start ) - pEntity->UpdateSelf( value ); - else - pEntity->UpdateSelfReturn( value ); - } - } - } -} - -void CMomentaryRotButton::UpdateSelf( float value ) -{ - BOOL fplaysound = FALSE; - - if ( !m_lastUsed ) - { - fplaysound = TRUE; - m_direction = -m_direction; - } - m_lastUsed = 1; - - pev->nextthink = pev->ltime + 0.1; - if ( m_direction > 0 && value >= 1.0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_end; - return; - } - else if ( m_direction < 0 && value <= 0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_start; - return; - } - - if (fplaysound) - PlaySound(); - - // HACKHACK -- If we're going slow, we'll get multiple player packets per frame, bump nexthink on each one to avoid stalling - if ( pev->nextthink < pev->ltime ) - pev->nextthink = pev->ltime + 0.1; - else - pev->nextthink += 0.1; - - pev->avelocity = (m_direction * pev->speed) * pev->movedir; - SetThink( &CMomentaryRotButton::Off ); -} - -void CMomentaryRotButton::UpdateTarget( float value ) -{ - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - CBaseEntity *pEntity = CBaseEntity::Instance(pentTarget); - if ( pEntity ) - { - pEntity->Use( this, this, USE_SET, value ); - } - } - } -} - -void CMomentaryRotButton::Off( void ) -{ - pev->avelocity = g_vecZero; - m_lastUsed = 0; - if ( FBitSet( pev->spawnflags, SF_PENDULUM_AUTO_RETURN ) && m_returnSpeed > 0 ) - { - SetThink( &CMomentaryRotButton::Return ); - pev->nextthink = pev->ltime + 0.1; - m_direction = -1; - } - else - SetThink( NULL ); -} - -void CMomentaryRotButton::Return( void ) -{ - float value = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; - - UpdateAllButtons( value, 0 ); // This will end up calling UpdateSelfReturn() n times, but it still works right - if ( value > 0 ) - UpdateTarget( value ); -} - - -void CMomentaryRotButton::UpdateSelfReturn( float value ) -{ - if ( value <= 0 ) - { - pev->avelocity = g_vecZero; - pev->angles = m_start; - pev->nextthink = -1; - SetThink( NULL ); - } - else - { - pev->avelocity = -m_returnSpeed * pev->movedir; - pev->nextthink = pev->ltime + 0.1; - } -} - - -//---------------------------------------------------------------- -// Spark -//---------------------------------------------------------------- - -class CEnvSpark : public CBaseEntity -{ -public: - void Spawn(void); - void Precache(void); - void EXPORT SparkThink(void); - void EXPORT SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue(KeyValueData *pkvd); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flDelay; -}; - - -TYPEDESCRIPTION CEnvSpark::m_SaveData[] = -{ - DEFINE_FIELD( CEnvSpark, m_flDelay, FIELD_FLOAT), -}; - -IMPLEMENT_SAVERESTORE( CEnvSpark, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(env_spark, CEnvSpark); -LINK_ENTITY_TO_CLASS(env_debris, CEnvSpark); - -void CEnvSpark::Spawn(void) -{ - SetThink( NULL ); - SetUse( NULL ); - - if (FBitSet(pev->spawnflags, 32)) // Use for on/off - { - if (FBitSet(pev->spawnflags, 64)) // Start on - { - SetThink(&CEnvSpark::SparkThink); // start sparking - SetUse(&CEnvSpark::SparkStop); // set up +USE to stop sparking - } - else - SetUse(&CEnvSpark::SparkStart); - } - else - SetThink(&CEnvSpark::SparkThink); - - pev->nextthink = gpGlobals->time + ( 0.1 + RANDOM_FLOAT ( 0, 1.5 ) ); - - if (m_flDelay <= 0) - m_flDelay = 1.5; - - Precache( ); -} - - -void CEnvSpark::Precache(void) -{ - PRECACHE_SOUND( "buttons/spark1.wav" ); - PRECACHE_SOUND( "buttons/spark2.wav" ); - PRECACHE_SOUND( "buttons/spark3.wav" ); - PRECACHE_SOUND( "buttons/spark4.wav" ); - PRECACHE_SOUND( "buttons/spark5.wav" ); - PRECACHE_SOUND( "buttons/spark6.wav" ); -} - -void CEnvSpark::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "MaxDelay")) - { - m_flDelay = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "killtarget") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else - CBaseEntity::KeyValue( pkvd ); -} - -void EXPORT CEnvSpark::SparkThink(void) -{ - pev->nextthink = gpGlobals->time + 0.1 + RANDOM_FLOAT (0, m_flDelay); - DoSpark( pev, pev->origin ); -} - -void EXPORT CEnvSpark::SparkStart(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetUse(&CEnvSpark::SparkStop); - SetThink(&CEnvSpark::SparkThink); - pev->nextthink = gpGlobals->time + (0.1 + RANDOM_FLOAT ( 0, m_flDelay)); -} - -void EXPORT CEnvSpark::SparkStop(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetUse(&CEnvSpark::SparkStart); - SetThink(NULL); -} - -#define SF_BTARGET_USE 0x0001 -#define SF_BTARGET_ON 0x0002 - -class CButtonTarget : public CBaseEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - int ObjectCaps( void ); - -}; - -LINK_ENTITY_TO_CLASS( button_target, CButtonTarget ); - -void CButtonTarget::Spawn( void ) -{ - pev->movetype = MOVETYPE_PUSH; - pev->solid = SOLID_BSP; - SET_MODEL(ENT(pev), STRING(pev->model)); - pev->takedamage = DAMAGE_YES; - - if ( FBitSet( pev->spawnflags, SF_BTARGET_ON ) ) - pev->frame = 1; -} - -void CButtonTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, (int)pev->frame ) ) - return; - pev->frame = 1-pev->frame; - if ( pev->frame ) - SUB_UseTargets( pActivator, USE_ON, 0 ); - else - SUB_UseTargets( pActivator, USE_OFF, 0 ); -} - - -int CButtonTarget :: ObjectCaps( void ) -{ - int caps = CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; - - if ( FBitSet(pev->spawnflags, SF_BTARGET_USE) ) - return caps | FCAP_IMPULSE_USE; - else - return caps; -} - - -int CButtonTarget::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Use( Instance(pevAttacker), this, USE_TOGGLE, 0 ); - - return 1; -} diff --git a/sdk/dlls/cbase.cpp b/sdk/dlls/cbase.cpp deleted file mode 100644 index f5d94cf..0000000 --- a/sdk/dlls/cbase.cpp +++ /dev/null @@ -1,771 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "client.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); - -extern "C" void PM_Move ( struct playermove_s *ppmove, int server ); -extern "C" void PM_Init ( struct playermove_s *ppmove ); -extern "C" char PM_FindTextureType( const char *name ); - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; - -static DLL_FUNCTIONS gFunctionTable = -{ - GameDLLInit, //pfnGameInit - DispatchSpawn, //pfnSpawn - DispatchThink, //pfnThink - DispatchUse, //pfnUse - DispatchTouch, //pfnTouch - DispatchBlocked, //pfnBlocked - DispatchKeyValue, //pfnKeyValue - DispatchSave, //pfnSave - DispatchRestore, //pfnRestore - DispatchObjectCollsionBox, //pfnAbsBox - - SaveWriteFields, //pfnSaveWriteFields - SaveReadFields, //pfnSaveReadFields - - SaveGlobalState, //pfnSaveGlobalState - RestoreGlobalState, //pfnRestoreGlobalState - ResetGlobalState, //pfnResetGlobalState - - ClientConnect, //pfnClientConnect - ClientDisconnect, //pfnClientDisconnect - ClientKill, //pfnClientKill - ClientPutInServer, //pfnClientPutInServer - ClientCommand, //pfnClientCommand - ClientUserInfoChanged, //pfnClientUserInfoChanged - ServerActivate, //pfnServerActivate - ServerDeactivate, //pfnServerDeactivate - - PlayerPreThink, //pfnPlayerPreThink - PlayerPostThink, //pfnPlayerPostThink - - StartFrame, //pfnStartFrame - ParmsNewLevel, //pfnParmsNewLevel - ParmsChangeLevel, //pfnParmsChangeLevel - - GetGameDescription, //pfnGetGameDescription Returns string describing current .dll game. - PlayerCustomization, //pfnPlayerCustomization Notifies .dll of new customization for player. - - SpectatorConnect, //pfnSpectatorConnect Called when spectator joins server - SpectatorDisconnect, //pfnSpectatorDisconnect Called when spectator leaves the server - SpectatorThink, //pfnSpectatorThink Called when spectator sends a command packet (usercmd_t) - - Sys_Error, //pfnSys_Error Called when engine has encountered an error - - PM_Move, //pfnPM_Move - PM_Init, //pfnPM_Init Server version of player movement initialization - PM_FindTextureType, //pfnPM_FindTextureType - - SetupVisibility, //pfnSetupVisibility Set up PVS and PAS for networking for this client - UpdateClientData, //pfnUpdateClientData Set up data sent only to specific client - AddToFullPack, //pfnAddToFullPack - CreateBaseline, //pfnCreateBaseline Tweak entity baseline for network encoding, allows setup of player baselines, too. - RegisterEncoders, //pfnRegisterEncoders Callbacks for network encoding - GetWeaponData, //pfnGetWeaponData - CmdStart, //pfnCmdStart - CmdEnd, //pfnCmdEnd - ConnectionlessPacket, //pfnConnectionlessPacket - GetHullBounds, //pfnGetHullBounds - CreateInstancedBaselines, //pfnCreateInstancedBaselines - InconsistentFile, //pfnInconsistentFile - AllowLagCompensation, //pfnAllowLagCompensation -}; - -static void SetObjectCollisionBox( entvars_t *pev ); - -extern "C" { - - int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ) -{ - if ( !pFunctionTable || interfaceVersion != INTERFACE_VERSION ) - { - return FALSE; - } - - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - return TRUE; -} - -int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ) -{ - if ( !pFunctionTable || *interfaceVersion != INTERFACE_VERSION ) - { - // Tell engine what version we had, so it can figure out who is out of date. - *interfaceVersion = INTERFACE_VERSION; - return FALSE; - } - - memcpy( pFunctionTable, &gFunctionTable, sizeof( DLL_FUNCTIONS ) ); - return TRUE; -} - -} - - -int DispatchSpawn( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if (pEntity) - { - // Initialize these or entities who don't link to the world won't have anything in here - pEntity->pev->absmin = pEntity->pev->origin - Vector(1,1,1); - pEntity->pev->absmax = pEntity->pev->origin + Vector(1,1,1); - - pEntity->Spawn(); - - // Try to get the pointer again, in case the spawn function deleted the entity. - // UNDONE: Spawn() should really return a code to ask that the entity be deleted, but - // that would touch too much code for me to do that right now. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity ) - { - if ( g_pGameRules && !g_pGameRules->IsAllowedToSpawn( pEntity ) ) - return -1; // return that this entity should be deleted - if ( pEntity->pev->flags & FL_KILLME ) - return -1; - } - - - // Handle global stuff here - if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) - return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive - // In this level & not dead, continue on as normal - } - else - { - // Spawned entities default to 'On' - gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); -// ALERT( at_console, "Added global entity %s (%s)\n", STRING(pEntity->pev->classname), STRING(pEntity->pev->globalname) ); - } - } - - } - - return 0; -} - -void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ) -{ - if ( !pkvd || !pentKeyvalue ) - return; - - EntvarsKeyvalue( VARS(pentKeyvalue), pkvd ); - - // If the key was an entity variable, or there's no class set yet, don't look for the object, it may - // not exist yet. - if ( pkvd->fHandled || pkvd->szClassName == NULL ) - return; - - // Get the actualy entity object - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentKeyvalue); - - if ( !pEntity ) - return; - - pEntity->KeyValue( pkvd ); -} - - -// HACKHACK -- this is a hack to keep the node graph entity from "touching" things (like triggers) -// while it builds the graph -BOOL gTouchDisabled = FALSE; -void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ) -{ - if ( gTouchDisabled ) - return; - - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentTouched); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if ( pEntity && pOther && ! ((pEntity->pev->flags | pOther->pev->flags) & FL_KILLME) ) - pEntity->Touch( pOther ); -} - - -void DispatchUse( edict_t *pentUsed, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pentUsed); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE(pentOther); - - if (pEntity && !(pEntity->pev->flags & FL_KILLME) ) - pEntity->Use( pOther, pOther, USE_TOGGLE, 0 ); -} - -void DispatchThink( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity) - { - if ( FBitSet( pEntity->pev->flags, FL_DORMANT ) ) - ALERT( at_error, "Dormant entity %s is thinking!!\n", STRING(pEntity->pev->classname) ); - - pEntity->Think(); - } -} - -void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE( pentBlocked ); - CBaseEntity *pOther = (CBaseEntity *)GET_PRIVATE( pentOther ); - - if (pEntity) - pEntity->Blocked( pOther ); -} - -void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity && pSaveData ) - { - ENTITYTABLE *pTable = &pSaveData->pTable[ pSaveData->currentIndex ]; - - if ( pTable->pent != pent ) - ALERT( at_error, "ENTITY TABLE OR INDEX IS WRONG!!!!\n" ); - - if ( pEntity->ObjectCaps() & FCAP_DONT_SAVE ) - return; - - // These don't use ltime & nextthink as times really, but we'll fudge around it. - if ( pEntity->pev->movetype == MOVETYPE_PUSH ) - { - float delta = pEntity->pev->nextthink - pEntity->pev->ltime; - pEntity->pev->ltime = gpGlobals->time; - pEntity->pev->nextthink = pEntity->pev->ltime + delta; - } - - pTable->location = pSaveData->size; // Remember entity position for file I/O - pTable->classname = pEntity->pev->classname; // Remember entity class for respawn - - CSave saveHelper( pSaveData ); - pEntity->Save( saveHelper ); - - pTable->size = pSaveData->size - pTable->location; // Size of entity block is data size written to block - } -} - - -// Find the matching global entity. Spit out an error if the designer made entities of -// different classes with the same global name -CBaseEntity *FindGlobalEntity( string_t classname, string_t globalname ) -{ - edict_t *pent = FIND_ENTITY_BY_STRING( NULL, "globalname", STRING(globalname) ); - CBaseEntity *pReturn = CBaseEntity::Instance( pent ); - if ( pReturn ) - { - if ( !FClassnameIs( pReturn->pev, STRING(classname) ) ) - { - ALERT( at_console, "Global entity found %s, wrong class %s\n", STRING(globalname), STRING(pReturn->pev->classname) ); - pReturn = NULL; - } - } - - return pReturn; -} - - -int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - - if ( pEntity && pSaveData ) - { - entvars_t tmpVars; - Vector oldOffset; - - CRestore restoreHelper( pSaveData ); - if ( globalEntity ) - { - CRestore tmpRestore( pSaveData ); - tmpRestore.PrecacheMode( 0 ); - tmpRestore.ReadEntVars( "ENTVARS", &tmpVars ); - - // HACKHACK - reset the save pointers, we're going to restore for real this time - pSaveData->size = pSaveData->pTable[pSaveData->currentIndex].location; - pSaveData->pCurrentData = pSaveData->pBaseData + pSaveData->size; - // ------------------- - - - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( tmpVars.globalname ); - - // Don't overlay any instance of the global that isn't the latest - // pSaveData->szCurrentMapName is the level this entity is coming from - // pGlobla->levelName is the last level the global entity was active in. - // If they aren't the same, then this global update is out of date. - if ( !FStrEq( pSaveData->szCurrentMapName, pGlobal->levelName ) ) - return 0; - - // Compute the new global offset - oldOffset = pSaveData->vecLandmarkOffset; - CBaseEntity *pNewEntity = FindGlobalEntity( tmpVars.classname, tmpVars.globalname ); - if ( pNewEntity ) - { -// ALERT( at_console, "Overlay %s with %s\n", STRING(pNewEntity->pev->classname), STRING(tmpVars.classname) ); - // Tell the restore code we're overlaying a global entity from another level - restoreHelper.SetGlobalMode( 1 ); // Don't overwrite global fields - pSaveData->vecLandmarkOffset = (pSaveData->vecLandmarkOffset - pNewEntity->pev->mins) + tmpVars.mins; - pEntity = pNewEntity;// we're going to restore this data OVER the old entity - pent = ENT( pEntity->pev ); - // Update the global table to say that the global definition of this entity should come from this level - gGlobalState.EntityUpdate( pEntity->pev->globalname, gpGlobals->mapname ); - } - else - { - // This entity will be freed automatically by the engine. If we don't do a restore on a matching entity (below) - // or call EntityUpdate() to move it to this level, we haven't changed global state at all. - return 0; - } - - } - - if ( pEntity->ObjectCaps() & FCAP_MUST_SPAWN ) - { - pEntity->Restore( restoreHelper ); - pEntity->Spawn(); - } - else - { - pEntity->Restore( restoreHelper ); - pEntity->Precache( ); - } - - // Again, could be deleted, get the pointer again. - pEntity = (CBaseEntity *)GET_PRIVATE(pent); - -#if 0 - if ( pEntity && pEntity->pev->globalname && globalEntity ) - { - ALERT( at_console, "Global %s is %s\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->model) ); - } -#endif - - // Is this an overriding global entity (coming over the transition), or one restoring in a level - if ( globalEntity ) - { -// ALERT( at_console, "After: %f %f %f %s\n", pEntity->pev->origin.x, pEntity->pev->origin.y, pEntity->pev->origin.z, STRING(pEntity->pev->model) ); - pSaveData->vecLandmarkOffset = oldOffset; - if ( pEntity ) - { - UTIL_SetOrigin( pEntity->pev, pEntity->pev->origin ); - pEntity->OverrideReset(); - } - } - else if ( pEntity && pEntity->pev->globalname ) - { - const globalentity_t *pGlobal = gGlobalState.EntityFromTable( pEntity->pev->globalname ); - if ( pGlobal ) - { - // Already dead? delete - if ( pGlobal->state == GLOBAL_DEAD ) - return -1; - else if ( !FStrEq( STRING(gpGlobals->mapname), pGlobal->levelName ) ) - { - pEntity->MakeDormant(); // Hasn't been moved to this level yet, wait but stay alive - } - // In this level & not dead, continue on as normal - } - else - { - ALERT( at_error, "Global Entity %s (%s) not in table!!!\n", STRING(pEntity->pev->globalname), STRING(pEntity->pev->classname) ); - // Spawned entities default to 'On' - gGlobalState.EntityAdd( pEntity->pev->globalname, gpGlobals->mapname, GLOBAL_ON ); - } - } - } - return 0; -} - - -void DispatchObjectCollsionBox( edict_t *pent ) -{ - CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent); - if (pEntity) - { - pEntity->SetObjectCollisionBox(); - } - else - SetObjectCollisionBox( &pent->v ); -} - - -void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CSave saveHelper( pSaveData ); - saveHelper.WriteFields( pname, pBaseData, pFields, fieldCount ); -} - - -void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - CRestore restoreHelper( pSaveData ); - restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); -} - - -edict_t * EHANDLE::Get( void ) -{ - if (m_pent) - { - if (m_pent->serialnumber == m_serialnumber) - return m_pent; - else - return NULL; - } - return NULL; -}; - -edict_t * EHANDLE::Set( edict_t *pent ) -{ - m_pent = pent; - if (pent) - m_serialnumber = m_pent->serialnumber; - return pent; -}; - - -EHANDLE :: operator CBaseEntity *() -{ - return (CBaseEntity *)GET_PRIVATE( Get( ) ); -}; - - -CBaseEntity * EHANDLE :: operator = (CBaseEntity *pEntity) -{ - if (pEntity) - { - m_pent = ENT( pEntity->pev ); - if (m_pent) - m_serialnumber = m_pent->serialnumber; - } - else - { - m_pent = NULL; - m_serialnumber = 0; - } - return pEntity; -} - -EHANDLE :: operator int () -{ - return Get() != NULL; -} - -CBaseEntity * EHANDLE :: operator -> () -{ - return (CBaseEntity *)GET_PRIVATE( Get( ) ); -} - - -// give health -int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) -{ - if (!pev->takedamage) - return 0; - -// heal - if ( pev->health >= pev->max_health ) - return 0; - - pev->health += flHealth; - - if (pev->health > pev->max_health) - pev->health = pev->max_health; - - return 1; -} - -// inflict damage on this entity. bitsDamageType indicates type of damage inflicted, ie: DMG_CRUSH - -int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - if (!pev->takedamage) - return 0; - - // UNDONE: some entity types may be immune or resistant to some bitsDamageType - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - else - // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( VecBModelOrigin(pev) ); - } - -// this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - -// save damage based on the target's armor level - -// figure momentum add (don't let hurt brushes or other triggers move player) - if ((!FNullEnt(pevInflictor)) && (pev->movetype == MOVETYPE_WALK || pev->movetype == MOVETYPE_STEP) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - - float flForce = flDamage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if (flForce > 1000.0) - flForce = 1000.0; - pev->velocity = pev->velocity + vecDir * flForce; - } - -// do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - Killed( pevAttacker, GIB_NORMAL ); - return 0; - } - - return 1; -} - - -void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->takedamage = DAMAGE_NO; - pev->deadflag = DEAD_DEAD; - UTIL_Remove( this ); -} - - -CBaseEntity *CBaseEntity::GetNextTarget( void ) -{ - if ( FStringNull( pev->target ) ) - return NULL; - edict_t *pTarget = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ); - if ( FNullEnt(pTarget) ) - return NULL; - - return Instance( pTarget ); -} - -// Global Savedata for Delay -TYPEDESCRIPTION CBaseEntity::m_SaveData[] = -{ - DEFINE_FIELD( CBaseEntity, m_pGoalEnt, FIELD_CLASSPTR ), - - DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION ), // UNDONE: Build table of these!!! - DEFINE_FIELD( CBaseEntity, m_pfnTouch, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnUse, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseEntity, m_pfnBlocked, FIELD_FUNCTION ), -}; - - -int CBaseEntity::Save( CSave &save ) -{ - if ( save.WriteEntVars( "ENTVARS", pev ) ) - return save.WriteFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - return 0; -} - -int CBaseEntity::Restore( CRestore &restore ) -{ - int status; - - status = restore.ReadEntVars( "ENTVARS", pev ); - if ( status ) - status = restore.ReadFields( "BASE", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - if ( pev->modelindex != 0 && !FStringNull(pev->model) ) - { - Vector mins, maxs; - mins = pev->mins; // Set model is about to destroy these - maxs = pev->maxs; - - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL(ENT(pev), STRING(pev->model)); - UTIL_SetSize(pev, mins, maxs); // Reset them - } - - return status; -} - - -// Initialize absmin & absmax to the appropriate box -void SetObjectCollisionBox( entvars_t *pev ) -{ - if ( (pev->solid == SOLID_BSP) && - (pev->angles.x || pev->angles.y|| pev->angles.z) ) - { // expand for rotation - float max, v; - int i; - - max = 0; - for (i=0 ; i<3 ; i++) - { - v = fabs( ((float *)pev->mins)[i]); - if (v > max) - max = v; - v = fabs( ((float *)pev->maxs)[i]); - if (v > max) - max = v; - } - for (i=0 ; i<3 ; i++) - { - ((float *)pev->absmin)[i] = ((float *)pev->origin)[i] - max; - ((float *)pev->absmax)[i] = ((float *)pev->origin)[i] + max; - } - } - else - { - pev->absmin = pev->origin + pev->mins; - pev->absmax = pev->origin + pev->maxs; - } - - pev->absmin.x -= 1; - pev->absmin.y -= 1; - pev->absmin.z -= 1; - pev->absmax.x += 1; - pev->absmax.y += 1; - pev->absmax.z += 1; -} - - -void CBaseEntity::SetObjectCollisionBox( void ) -{ - ::SetObjectCollisionBox( pev ); -} - - -int CBaseEntity :: Intersects( CBaseEntity *pOther ) -{ - if ( pOther->pev->absmin.x > pev->absmax.x || - pOther->pev->absmin.y > pev->absmax.y || - pOther->pev->absmin.z > pev->absmax.z || - pOther->pev->absmax.x < pev->absmin.x || - pOther->pev->absmax.y < pev->absmin.y || - pOther->pev->absmax.z < pev->absmin.z ) - return 0; - return 1; -} - -void CBaseEntity :: MakeDormant( void ) -{ - SetBits( pev->flags, FL_DORMANT ); - - // Don't touch - pev->solid = SOLID_NOT; - // Don't move - pev->movetype = MOVETYPE_NONE; - // Don't draw - SetBits( pev->effects, EF_NODRAW ); - // Don't think - pev->nextthink = 0; - // Relink - UTIL_SetOrigin( pev, pev->origin ); -} - -int CBaseEntity :: IsDormant( void ) -{ - return FBitSet( pev->flags, FL_DORMANT ); -} - -BOOL CBaseEntity :: IsInWorld( void ) -{ - // position - if (pev->origin.x >= 4096) return FALSE; - if (pev->origin.y >= 4096) return FALSE; - if (pev->origin.z >= 4096) return FALSE; - if (pev->origin.x <= -4096) return FALSE; - if (pev->origin.y <= -4096) return FALSE; - if (pev->origin.z <= -4096) return FALSE; - // speed - if (pev->velocity.x >= 2000) return FALSE; - if (pev->velocity.y >= 2000) return FALSE; - if (pev->velocity.z >= 2000) return FALSE; - if (pev->velocity.x <= -2000) return FALSE; - if (pev->velocity.y <= -2000) return FALSE; - if (pev->velocity.z <= -2000) return FALSE; - - return TRUE; -} - -int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) -{ - if ( useType != USE_TOGGLE && useType != USE_SET ) - { - if ( (currentState && useType == USE_ON) || (!currentState && useType == USE_OFF) ) - return 0; - } - return 1; -} - - -int CBaseEntity :: DamageDecal( int bitsDamageType ) -{ - if ( pev->rendermode == kRenderTransAlpha ) - return -1; - - if ( pev->rendermode != kRenderNormal ) - return DECAL_BPROOF1; - - return DECAL_GUNSHOT1 + RANDOM_LONG(0,4); -} - - - -// NOTE: szName must be a pointer to constant memory, e.g. "monster_class" because the entity -// will keep a pointer to it after this call. -CBaseEntity * CBaseEntity::Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) -{ - edict_t *pent; - CBaseEntity *pEntity; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szName )); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in Create!\n" ); - return NULL; - } - pEntity = Instance( pent ); - pEntity->pev->owner = pentOwner; - pEntity->pev->origin = vecOrigin; - pEntity->pev->angles = vecAngles; - DispatchSpawn( pEntity->edict() ); - return pEntity; -} - - diff --git a/sdk/dlls/cbase.h b/sdk/dlls/cbase.h deleted file mode 100644 index e7b0483..0000000 --- a/sdk/dlls/cbase.h +++ /dev/null @@ -1,802 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -Class Hierachy - -CBaseEntity - CBaseDelay - CBaseToggle - CBaseItem - CBaseMonster - CBaseCycler - CBasePlayer - CBaseGroup -*/ - -#define MAX_PATH_SIZE 10 // max number of nodes available for a path. - -// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) -#define FCAP_CUSTOMSAVE 0x00000001 -#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions -#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore -#define FCAP_DONT_SAVE 0x80000000 // Don't save this -#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player -#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player -#define FCAP_ONOFF_USE 0x00000020 // can be used by the player -#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) -#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource) - -// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! -#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions - -#include "archtypes.h" // DAL -#include "saverestore.h" -#include "schedule.h" - -#ifndef MONSTEREVENT_H -#include "monsterevent.h" -#endif - -// C functions for external declarations that call the appropriate C++ methods - -#ifndef CBASE_DLLEXPORT -#ifdef _WIN32 -#define CBASE_DLLEXPORT _declspec( dllexport ) -#else -#define CBASE_DLLEXPORT __attribute__ ((visibility("default"))) -#endif -#endif - -#define EXPORT CBASE_DLLEXPORT - -extern "C" CBASE_DLLEXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); -extern "C" CBASE_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); - -extern int DispatchSpawn( edict_t *pent ); -extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); -extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ); -extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther ); -extern void DispatchThink( edict_t *pent ); -extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ); -extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ); -extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); -extern void DispatchObjectCollsionBox( edict_t *pent ); -extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); -extern void SaveGlobalState( SAVERESTOREDATA *pSaveData ); -extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData ); -extern void ResetGlobalState( void ); - -typedef enum { USE_OFF = 0, USE_ON = 1, USE_SET = 2, USE_TOGGLE = 3 } USE_TYPE; - -extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -typedef void (CBaseEntity::*BASEPTR)(void); -typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); -typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -// For CLASSIFY -#define CLASS_NONE 0 -#define CLASS_MACHINE 1 -#define CLASS_PLAYER 2 -#define CLASS_HUMAN_PASSIVE 3 -#define CLASS_HUMAN_MILITARY 4 -#define CLASS_ALIEN_MILITARY 5 -#define CLASS_ALIEN_PASSIVE 6 -#define CLASS_ALIEN_MONSTER 7 -#define CLASS_ALIEN_PREY 8 -#define CLASS_ALIEN_PREDATOR 9 -#define CLASS_INSECT 10 -#define CLASS_PLAYER_ALLY 11 -#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players -#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace -#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. - -class CBaseEntity; -class CBaseMonster; -class CBasePlayerItem; -class CSquadMonster; - - -#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn. - -// -// EHANDLE. Safe way to point to CBaseEntities who may die between frames -// -class EHANDLE -{ -private: - edict_t *m_pent; - int m_serialnumber; -public: - edict_t *Get( void ); - edict_t *Set( edict_t *pent ); - - operator int (); - - operator CBaseEntity *(); - - CBaseEntity * operator = (CBaseEntity *pEntity); - CBaseEntity * operator ->(); -}; - - -// -// Base Entity. All entity types derive from this -// -class CBaseEntity -{ -public: - // Constructor. Set engine to use C/C++ callback functions - // pointers to engine data - entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it - - // path corners - CBaseEntity *m_pGoalEnt;// path corner we are heading towards - CBaseEntity *m_pLink;// used for temporary link-list operations. - - // initialization functions - virtual void Spawn( void ) { return; } - virtual void Precache( void ) { return; } - virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; } - virtual void Activate( void ) {} - - // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) - virtual void SetObjectCollisionBox( void ); - -// Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames -// still realize that they are teammates. (overridden for monsters that form groups) - virtual int Classify ( void ) { return CLASS_NONE; }; - virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died. - - - static TYPEDESCRIPTION m_SaveData[]; - - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;} - virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;} - virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;} - virtual int GetToggleState( void ) { return TS_AT_TOP; } - virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {} - virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {} - virtual BOOL AddPlayerItem( CBasePlayerItem *pItem ) { return 0; } - virtual BOOL RemovePlayerItem( CBasePlayerItem *pItem ) { return 0; } - virtual int GiveAmmo( int iAmount, const char *szName, int iMax ) { return -1; }; - virtual float GetDelay( void ) { return 0; } - virtual int IsMoving( void ) { return pev->velocity != g_vecZero; } - virtual void OverrideReset( void ) {} - virtual int DamageDecal( int bitsDamageType ); - // This is ONLY used by the node graph to test movement through a door - virtual void SetToggleState( int state ) {} - virtual void StartSneaking( void ) {} - virtual void StopSneaking( void ) {} - virtual BOOL OnControls( entvars_t *pev ) { return FALSE; } - virtual BOOL IsSneaking( void ) { return FALSE; } - virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } - virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; } - virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); } - virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); } - virtual BOOL IsInWorld( void ); - virtual BOOL IsPlayer( void ) { return FALSE; } - virtual BOOL IsNetClient( void ) { return FALSE; } - virtual const char *TeamID( void ) { return ""; } - - -// virtual void SetActivator( CBaseEntity *pActivator ) {} - virtual CBaseEntity *GetNextTarget( void ); - - // fundamental callbacks - void (CBaseEntity ::*m_pfnThink)(void); - void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); - void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); - - virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); }; - virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); }; - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) - { - if (m_pfnUse) - (this->*m_pfnUse)( pActivator, pCaller, useType, value ); - } - virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; - - // allow engine to allocate instance data - void *operator new( size_t stAllocateBlock, entvars_t *pev ) - { - return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); - }; - - // don't use this. -#if defined(_MSC_VER) && _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher - void operator delete(void *pMem, entvars_t *pev) - { - pev->flags |= FL_KILLME; - }; -#endif - - void UpdateOnRemove( void ); - - // common member functions - void EXPORT SUB_Remove( void ); - void EXPORT SUB_DoNothing( void ); - void EXPORT SUB_StartFadeOut ( void ); - void EXPORT SUB_FadeOut ( void ); - void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } - int ShouldToggle( USE_TYPE useType, BOOL currentState ); - void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL ); - Vector FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int shared_rand = 0 ); - - virtual CBaseEntity *Respawn( void ) { return NULL; } - - void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); - // Do the bounding boxes of these two intersect? - int Intersects( CBaseEntity *pOther ); - void MakeDormant( void ); - int IsDormant( void ); - BOOL IsLockedByMaster( void ) { return FALSE; } - - static CBaseEntity *Instance( edict_t *pent ) - { - if ( !pent ) - pent = ENT(0); - CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); - return pEnt; - } - - static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } - static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } - - CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) - { - CBaseEntity *pEntity = Instance( pevMonster ); - if ( pEntity ) - return pEntity->MyMonsterPointer(); - return NULL; - } - CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) - { - CBaseEntity *pEntity = Instance( pentMonster ); - if ( pEntity ) - return pEntity->MyMonsterPointer(); - return NULL; - } - - - // Ugly code to lookup all functions to make sure they are exported when set. -#ifdef _DEBUG - void FunctionCheck( void *pFunction, char *name ) - { - if (pFunction && !NAME_FOR_FUNCTION((uint32)pFunction) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (uint32)pFunction ); - } - - BASEPTR ThinkSet( BASEPTR func, char *name ) - { - m_pfnThink = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); - return func; - } - ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnTouch = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name ); - return func; - } - USEPTR UseSet( USEPTR func, char *name ) - { - m_pfnUse = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); - return func; - } - ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) - { - m_pfnBlocked = func; - FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); - return func; - } - -#endif - - - // virtual functions used by a few classes - - // used by monsters that are created by the MonsterMaker - virtual void UpdateOwner( void ) { return; }; - - - // - static CBaseEntity *Create( const char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); - - virtual BOOL FBecomeProne( void ) {return FALSE;}; - edict_t *edict() { return ENT( pev ); }; - EOFFSET eoffset( ) { return OFFSET( pev ); }; - int entindex( ) { return ENTINDEX( edict() ); }; - - virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity - virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes - virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at - - virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); }; - - virtual BOOL FVisible ( CBaseEntity *pEntity ); - virtual BOOL FVisible ( const Vector &vecOrigin ); - - //We use this variables to store each ammo count. - int ammo_9mm; - int ammo_357; - int ammo_bolts; - int ammo_buckshot; - int ammo_rockets; - int ammo_uranium; - int ammo_hornets; - int ammo_argrens; - //Special stuff for grenades and satchels. - float m_flStartThrow; - float m_flReleaseThrow; - int m_chargeReady; - int m_fInAttack; - - enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; - int m_fireState; -}; - - - -// Ugly technique to override base member functions -// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a -// member function of a base class. static_cast is a sleezy way around that problem. - -#ifdef _DEBUG - -#define SetThink( a ) ThinkSet( static_cast (a), #a ) -#define SetTouch( a ) TouchSet( static_cast (a), #a ) -#define SetUse( a ) UseSet( static_cast (a), #a ) -#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) - -#else - -#define SetThink( a ) m_pfnThink = static_cast (a) -#define SetTouch( a ) m_pfnTouch = static_cast (a) -#define SetUse( a ) m_pfnUse = static_cast (a) -#define SetBlocked( a ) m_pfnBlocked = static_cast (a) - -#endif - - -class CPointEntity : public CBaseEntity -{ -public: - void Spawn( void ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -private: -}; - - -typedef struct locksounds // sounds that doors and buttons make when locked/unlocked -{ - string_t sLockedSound; // sound a door makes when it's locked - string_t sLockedSentence; // sentence group played when door is locked - string_t sUnlockedSound; // sound a door makes when it's unlocked - string_t sUnlockedSentence; // sentence group played when door is unlocked - - int iLockedSentence; // which sentence in sentence group to play next - int iUnlockedSentence; // which sentence in sentence group to play next - - float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds - float flwaitSentence; // time delay between playing consecutive sentences - BYTE bEOFLocked; // true if hit end of list of locked sentences - BYTE bEOFUnlocked; // true if hit end of list of unlocked sentences -} locksound_t; - -void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton); - -// -// MultiSouce -// - -#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned. -#define MS_MAX_TARGETS 32 - -class CMultiSource : public CPointEntity -{ -public: - void Spawn( ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return (CPointEntity::ObjectCaps() | FCAP_MASTER); } - BOOL IsTriggered( CBaseEntity *pActivator ); - void EXPORT Register( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - EHANDLE m_rgEntities[MS_MAX_TARGETS]; - int m_rgTriggered[MS_MAX_TARGETS]; - - int m_iTotal; - string_t m_globalstate; -}; - - -// -// generic Delay entity. -// -class CBaseDelay : public CBaseEntity -{ -public: - float m_flDelay; - int m_iszKillTarget; - - virtual void KeyValue( KeyValueData* pkvd); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - // common member functions - void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); - void EXPORT DelayThink( void ); -}; - - -class CBaseAnimating : public CBaseDelay -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // Basic Monster Animation functions - float StudioFrameAdvance( float flInterval = 0.0 ); // accumulate animation frame time from last time called until now - int GetSequenceFlags( void ); - int LookupActivity ( int activity ); - int LookupActivityHeaviest ( int activity ); - int LookupSequence ( const char *label ); - void ResetSequenceInfo ( ); - void DispatchAnimEvents ( float flFutureInterval = 0.1 ); // Handle events that have happend since last time called up until X seconds into the future - virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; }; - float SetBoneController ( int iController, float flValue ); - void InitBoneControllers ( void ); - float SetBlending ( int iBlender, float flValue ); - void GetBonePosition ( int iBone, Vector &origin, Vector &angles ); - void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 ); - int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ); - void GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); - void SetBodygroup( int iGroup, int iValue ); - int GetBodygroup( int iGroup ); - int ExtractBbox( int sequence, float *mins, float *maxs ); - void SetSequenceBox( void ); - - // animation needs - float m_flFrameRate; // computed FPS for current sequence - float m_flGroundSpeed; // computed linear movement rate for current sequence - float m_flLastEventCheck; // last time the event list was checked - BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry - BOOL m_fSequenceLoops; // true if the sequence loops -}; - - -// -// generic Toggle entity. -// -#define SF_ITEM_USE_ONLY 256 // ITEM_USE_ONLY = BUTTON_USE_ONLY = DOOR_USE_ONLY!!! - -class CBaseToggle : public CBaseAnimating -{ -public: - void KeyValue( KeyValueData *pkvd ); - - TOGGLE_STATE m_toggle_state; - float m_flActivateFinished;//like attack_finished, but for doors - float m_flMoveDistance;// how far a door should slide or rotate - float m_flWait; - float m_flLip; - float m_flTWidth;// for plats - float m_flTLength;// for plats - - Vector m_vecPosition1; - Vector m_vecPosition2; - Vector m_vecAngle1; - Vector m_vecAngle2; - - int m_cTriggersLeft; // trigger_counter only, # of activations remaining - float m_flHeight; - EHANDLE m_hActivator; - void (CBaseToggle::*m_pfnCallWhenMoveDone)(void); - Vector m_vecFinalDest; - Vector m_vecFinalAngle; - - int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - virtual int GetToggleState( void ) { return m_toggle_state; } - virtual float GetDelay( void ) { return m_flWait; } - - // common member functions - void LinearMove( Vector vecDest, float flSpeed ); - void EXPORT LinearMoveDone( void ); - void AngularMove( Vector vecDestAngle, float flSpeed ); - void EXPORT AngularMoveDone( void ); - BOOL IsLockedByMaster( void ); - - static float AxisValue( int flags, const Vector &angles ); - static void AxisDir( entvars_t *pev ); - static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ); - - string_t m_sMaster; // If this button has a master switch, this is the targetname. - // A master switch must be of the multisource type. If all - // of the switches in the multisource have been triggered, then - // the button will be allowed to operate. Otherwise, it will be - // deactivated. -}; -#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) - - -// people gib if their health is <= this at the time of death -#define GIB_HEALTH_VALUE -30 - -#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time -#define MAX_OLD_ENEMIES 4 // how many old enemies to remember - -#define bits_CAP_DUCK ( 1 << 0 )// crouch -#define bits_CAP_JUMP ( 1 << 1 )// jump/leap -#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways) -#define bits_CAP_SQUAD ( 1 << 3 )// can form squads -#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water -#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes -#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers -#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds -#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors -#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors -#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0 - -#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1 -#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2 -#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1 -#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2 - -#define bits_CAP_FLY ( 1 << 15)// can fly, move all around - -#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) - -// used by suit voice to indicate damage sustained and repaired type to player - -// instant damage - -#define DMG_GENERIC 0 // generic damage was done -#define DMG_CRUSH (1 << 0) // crushed by falling or moving object -#define DMG_BULLET (1 << 1) // shot -#define DMG_SLASH (1 << 2) // cut, clawed, stabbed -#define DMG_BURN (1 << 3) // heat burned -#define DMG_FREEZE (1 << 4) // frozen -#define DMG_FALL (1 << 5) // fell too far -#define DMG_BLAST (1 << 6) // explosive blast damage -#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt -#define DMG_SHOCK (1 << 8) // electric shock -#define DMG_SONIC (1 << 9) // sound pulse shockwave -#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam -#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death -#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. -#define DMG_DROWN (1 << 14) // Drowning -// time-based damage -#define DMG_TIMEBASED (~(0x3fff)) // mask for time-based damage - -#define DMG_PARALYZE (1 << 15) // slows affected creature down -#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad -#define DMG_POISON (1 << 17) // blood poisioning -#define DMG_RADIATION (1 << 18) // radiation exposure -#define DMG_DROWNRECOVER (1 << 19) // drowning recovery -#define DMG_ACID (1 << 20) // toxic chemicals or acid burns -#define DMG_SLOWBURN (1 << 21) // in an oven -#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer -#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) - -// these are the damage types that are allowed to gib corpses -#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB ) - -// these are the damage types that have client hud art -#define DMG_SHOWNHUD (DMG_POISON | DMG_ACID | DMG_FREEZE | DMG_SLOWFREEZE | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK) - -// NOTE: tweak these values based on gameplay feedback: - -#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage -#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval - -#define NERVEGAS_DURATION 2 -#define NERVEGAS_DAMAGE 5.0 - -#define POISON_DURATION 5 -#define POISON_DAMAGE 2.0 - -#define RADIATION_DURATION 2 -#define RADIATION_DAMAGE 1.0 - -#define ACID_DURATION 2 -#define ACID_DAMAGE 5.0 - -#define SLOWBURN_DURATION 2 -#define SLOWBURN_DAMAGE 1.0 - -#define SLOWFREEZE_DURATION 2 -#define SLOWFREEZE_DAMAGE 1.0 - - -#define itbd_Paralyze 0 -#define itbd_NerveGas 1 -#define itbd_Poison 2 -#define itbd_Radiation 3 -#define itbd_DrownRecover 4 -#define itbd_Acid 5 -#define itbd_SlowBurn 6 -#define itbd_SlowFreeze 7 -#define CDMG_TIMEBASED 8 - -// when calling KILLED(), a value that governs gib behavior is expected to be -// one of these three values -#define GIB_NORMAL 0// gib if entity was overkilled -#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) -#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite ) - -class CBaseMonster; -class CCineMonster; -class CSound; - -#include "basemonster.h" - - -const char *ButtonSound( int sound ); // get string of button sound number - - -// -// Generic Button -// -class CBaseButton : public CBaseToggle -{ -public: - void Spawn( void ); - virtual void Precache( void ); - void RotSpawn( void ); - virtual void KeyValue( KeyValueData* pkvd); - - void ButtonActivate( ); - void SparkSoundCache( void ); - - void EXPORT ButtonShot( void ); - void EXPORT ButtonTouch( CBaseEntity *pOther ); - void EXPORT ButtonSpark ( void ); - void EXPORT TriggerAndWait( void ); - void EXPORT ButtonReturn( void ); - void EXPORT ButtonBackHome( void ); - void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN }; - BUTTON_CODE ButtonResponseToTouch( void ); - - static TYPEDESCRIPTION m_SaveData[]; - // Buttons that don't take damage can be IMPULSE used - virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); } - - BOOL m_fStayPushed; // button stays pushed in until touched again? - BOOL m_fRotating; // a rotating button? default is a sliding button. - - string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array. - // when this button is touched, it's target entity's TARGET field will be set - // to the button's ChangeTarget. This allows you to make a func_train switch paths, etc. - - locksound_t m_ls; // door lock sounds - - BYTE m_bLockedSound; // ordinals from entity selection - BYTE m_bLockedSentence; - BYTE m_bUnlockedSound; - BYTE m_bUnlockedSentence; - int m_sounds; -}; - -// -// Weapons -// - -#define BAD_WEAPON 0x00007FFF - -// -// Converts a entvars_t * to a class pointer -// It will allocate the class and entity if necessary -// -template T * GetClassPtr( T *a ) -{ - entvars_t *pev = (entvars_t *)a; - - // allocate entity if necessary - if (pev == NULL) - pev = VARS(CREATE_ENTITY()); - - // get the private data - a = (T *)GET_PRIVATE(ENT(pev)); - - if (a == NULL) - { - // allocate private data - a = new(pev) T; - a->pev = pev; - } - return a; -} - - -/* -bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA -bit_MONSTER_DATA -bit_DELAY_DATA -bit_TOGGLE_DATA | bit_DELAY_DATA | bit_MONSTER_DATA -bit_PLAYER_DATA | bit_MONSTER_DATA -bit_MONSTER_DATA | CYCLER_DATA -bit_LIGHT_DATA -path_corner_data -bit_MONSTER_DATA | wildcard_data -bit_MONSTER_DATA | bit_GROUP_DATA -boid_flock_data -boid_data -CYCLER_DATA -bit_ITEM_DATA -bit_ITEM_DATA | func_hud_data -bit_TOGGLE_DATA | bit_ITEM_DATA -EOFFSET -env_sound_data -env_sound_data -push_trigger_data -*/ - -#define TRACER_FREQ 4 // Tracers fire every 4 bullets - -typedef struct _SelAmmo -{ - BYTE Ammo1Type; - BYTE Ammo1; - BYTE Ammo2Type; - BYTE Ammo2; -} SelAmmo; - - -// this moved here from world.cpp, to allow classes to be derived from it -//======================= -// CWorld -// -// This spawns first when each level begins. -//======================= -class CWorld : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); -}; diff --git a/sdk/dlls/cdll_dll.h b/sdk/dlls/cdll_dll.h deleted file mode 100644 index 920fa29..0000000 --- a/sdk/dlls/cdll_dll.h +++ /dev/null @@ -1,46 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cdll_dll.h - -// this file is included by both the game-dll and the client-dll, - -#ifndef CDLL_DLL_H -#define CDLL_DLL_H - -#define MAX_WEAPONS 32 // ??? - -#define MAX_WEAPON_SLOTS 5 // hud item selection slots -#define MAX_ITEM_TYPES 6 // hud item selection slots - -#define MAX_ITEMS 5 // hard coded item types - -#define HIDEHUD_WEAPONS ( 1<<0 ) -#define HIDEHUD_FLASHLIGHT ( 1<<1 ) -#define HIDEHUD_ALL ( 1<<2 ) -#define HIDEHUD_HEALTH ( 1<<3 ) - -#define MAX_AMMO_TYPES 32 // ??? -#define MAX_AMMO_SLOTS 32 // not really slots - -#define HUD_PRINTNOTIFY 1 -#define HUD_PRINTCONSOLE 2 -#define HUD_PRINTTALK 3 -#define HUD_PRINTCENTER 4 - - -#define WEAPON_SUIT 31 - -#endif diff --git a/sdk/dlls/client.cpp b/sdk/dlls/client.cpp deleted file mode 100644 index 2e55746..0000000 --- a/sdk/dlls/client.cpp +++ /dev/null @@ -1,1915 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to -// have one without a hardcoded player.mdl in tf_client.cpp - -/* - -===== client.cpp ======================================================== - - client/server game specific stuff - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "player.h" -#include "spectator.h" -#include "client.h" -#include "soundent.h" -#include "gamerules.h" -#include "game.h" -#include "customentity.h" -#include "weapons.h" -#include "weaponinfo.h" -#include "usercmd.h" -#include "netadr.h" -#include "pm_shared.h" - -#if !defined ( _WIN32 ) -#include -#endif - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL int g_iSkillLevel; -extern DLL_GLOBAL ULONG g_ulFrameCount; - -extern void CopyToBodyQue(entvars_t* pev); -extern int giPrecacheGrunt; -extern int gmsgSayText; - -extern cvar_t allow_spectators; - -extern int g_teamplay; - -void LinkUserMessages( void ); - -/* - * used by kill command and disconnect command - * ROBIN: Moved here from player.cpp, to allow multiple player models - */ -void set_suicide_frame(entvars_t* pev) -{ - if (!FStrEq(STRING(pev->model), "models/player.mdl")) - return; // allready gibbed - -// pev->frame = $deatha11; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - pev->deadflag = DEAD_DEAD; - pev->nextthink = -1; -} - - -/* -=========== -ClientConnect - -called when a player connects to a server -============ -*/ -BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); - -// a client connecting during an intermission can cause problems -// if (intermission_running) -// ExitIntermission (); - -} - - -/* -=========== -ClientDisconnect - -called when a player disconnects from a server - -GLOBALS ASSUMED SET: g_fGameOver -============ -*/ -void ClientDisconnect( edict_t *pEntity ) -{ - if (g_fGameOver) - return; - - char text[256] = "" ; - if ( pEntity->v.netname ) - _snprintf( text, sizeof(text), "- %s has left the game\n", STRING(pEntity->v.netname) ); - text[ sizeof(text) - 1 ] = 0; - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - CSound *pSound; - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) ); - { - // since this client isn't around to think anymore, reset their sound. - if ( pSound ) - { - pSound->Reset(); - } - } - -// since the edict doesn't get deleted, fix it so it doesn't interfere. - pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim - pEntity->v.solid = SOLID_NOT;// nonsolid - UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin ); - - g_pGameRules->ClientDisconnected( pEntity ); -} - - -// called by ClientKill and DeadThink -void respawn(entvars_t* pev, BOOL fCopyCorpse) -{ - if (gpGlobals->coop || gpGlobals->deathmatch) - { - if ( fCopyCorpse ) - { - // make a copy of the dead body for appearances sake - CopyToBodyQue(pev); - } - - // respawn player - GetClassPtr( (CBasePlayer *)pev)->Spawn( ); - } - else - { // restart the entire server - SERVER_COMMAND("reload\n"); - } -} - -/* -============ -ClientKill - -Player entered the suicide command - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -============ -*/ -void ClientKill( edict_t *pEntity ) -{ - entvars_t *pev = &pEntity->v; - - CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev ); - - if ( pl->m_fNextSuicideTime > gpGlobals->time ) - return; // prevent suiciding too ofter - - pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding - - // have the player kill themself - pev->health = 0; - pl->Killed( pev, GIB_NEVER ); - -// pev->modelindex = g_ulModelIndexPlayer; -// pev->frags -= 2; // extra penalty -// respawn( pev ); -} - -/* -=========== -ClientPutInServer - -called each time a player is spawned -============ -*/ -void ClientPutInServer( edict_t *pEntity ) -{ - CBasePlayer *pPlayer; - - entvars_t *pev = &pEntity->v; - - pPlayer = GetClassPtr((CBasePlayer *)pev); - pPlayer->SetCustomDecalFrames(-1); // Assume none; - - // Allocate a CBasePlayer for pev, and call spawn - pPlayer->Spawn() ; - - // Reset interpolation during first frame - pPlayer->pev->effects |= EF_NOINTERP; - - pPlayer->pev->iuser1 = 0; // disable any spec modes - pPlayer->pev->iuser2 = 0; -} - -#include "voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - - - -#if defined( _MSC_VER ) || defined( WIN32 ) -typedef wchar_t uchar16; -typedef unsigned int uchar32; -#else -typedef unsigned short uchar16; -typedef wchar_t uchar32; -#endif - -//----------------------------------------------------------------------------- -// Purpose: determine if a uchar32 represents a valid Unicode code point -//----------------------------------------------------------------------------- -bool Q_IsValidUChar32( uchar32 uVal ) -{ - // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves, - // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range - return ( ( uVal - 0x0u ) < 0x110000u ) && ( (uVal - 0x00D800u) > 0x7FFu ) && ( (uVal & 0xFFFFu) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu ); -} - - -// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences -// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence. -int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut ) -{ - const uint8 *pUTF8 = (const uint8 *)pUTF8_; - - int nBytes = 1; - uint32 uValue = pUTF8[0]; - uint32 uMinValue = 0; - - // 0....... single byte - if ( uValue < 0x80 ) - goto decodeFinishedNoCheck; - - // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...) - if ( (uValue - 0xC0u) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80; - nBytes = 2; - uMinValue = 0x80; - - // 110..... two-byte lead byte - if ( !( uValue & (0x20 << 6) ) ) - goto decodeFinished; - - // Expecting at least a three-byte sequence - if ( ( pUTF8[2] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80; - nBytes = 3; - uMinValue = 0x800; - - // 1110.... three-byte lead byte - if ( !( uValue & (0x10 << 12) ) ) - goto decodeFinishedMaybeCESU8; - - // Expecting a four-byte sequence, longest permissible in UTF-8 - if ( ( pUTF8[3] & 0xC0 ) != 0x80 ) - goto decodeError; - - uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80; - nBytes = 4; - uMinValue = 0x10000; - - // 11110... four-byte lead byte. fall through to finished. - -decodeFinished: - if ( uValue >= uMinValue && Q_IsValidUChar32( uValue ) ) - { -decodeFinishedNoCheck: - uValueOut = uValue; - bErrorOut = false; - return nBytes; - } -decodeError: - uValueOut = '?'; - bErrorOut = true; - return nBytes; - -decodeFinishedMaybeCESU8: - // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards? - // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all. - if ( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (uint8)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 ) - { - uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (uint8)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80; - nBytes = 6; - uMinValue = 0x10000; - } - goto decodeFinished; -} - - - -//----------------------------------------------------------------------------- -// Purpose: Returns true if UTF-8 string contains invalid sequences. -//----------------------------------------------------------------------------- -bool Q_UnicodeValidate( const char *pUTF8 ) -{ - bool bError = false; - while ( *pUTF8 ) - { - uchar32 uVal; - // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences. - // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error. - int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError ); - if ( bError || nCharSize == 6 ) - return false; - pUTF8 += nCharSize; - } - return true; -} - -//// HOST_SAY -// String comes in as -// say blah blah blah -// or as -// blah blah blah -// -void Host_Say( edict_t *pEntity, int teamonly ) -{ - CBasePlayer *client; - int j; - char *p; - char text[128]; - char szTemp[256]; - const char *cpSay = "say"; - const char *cpSayTeam = "say_team"; - const char *pcmd = CMD_ARGV(0); - - // We can get a raw string now, without the "say " prepended - if ( CMD_ARGC() == 0 ) - return; - - entvars_t *pev = &pEntity->v; - CBasePlayer* player = GetClassPtr((CBasePlayer *)pev); - - //Not yet. - if ( player->m_flNextChatTime > gpGlobals->time ) - return; - - if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) - { - if ( CMD_ARGC() >= 2 ) - { - p = (char *)CMD_ARGS(); - } - else - { - // say with a blank message, nothing to do - return; - } - } - else // Raw text, need to prepend argv[0] - { - if ( CMD_ARGC() >= 2 ) - { - sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() ); - } - else - { - // Just a one word command, use the first word...sigh - sprintf( szTemp, "%s", ( char * )pcmd ); - } - p = szTemp; - } - -// remove quotes if present - if (*p == '"') - { - p++; - p[strlen(p)-1] = 0; - } - -// make sure the text has content - - if ( !p || !p[0] || !Q_UnicodeValidate ( p ) ) - return; // no character found, so say nothing - -// turn on color set 2 (color on, no sound) - // turn on color set 2 (color on, no sound) - if ( player->IsObserver() && ( teamonly ) ) - sprintf( text, "%c(SPEC) %s: ", 2, STRING( pEntity->v.netname ) ); - else if ( teamonly ) - sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); - else - sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); - - j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator - if ( (int)strlen(p) > j ) - p[j] = 0; - - strcat( text, p ); - strcat( text, "\n" ); - - - player->m_flNextChatTime = gpGlobals->time + CHAT_INTERVAL; - - // loop through all players - // Start with the first player. - // This may return the world in single player if the client types something between levels or during spawn - // so check it, or it will infinite loop - - client = NULL; - while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) ) - { - if ( !client->pev ) - continue; - - if ( client->edict() == pEntity ) - continue; - - if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) - continue; - - // can the receiver hear the sender? or has he muted him? - if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) - continue; - - if ( !player->IsObserver() && teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) - continue; - - // Spectators can only talk to other specs - if ( player->IsObserver() && teamonly ) - if ( !client->IsObserver() ) - continue; - - MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - } - - // print to the sending client - MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - - // echo to server console - g_engfuncs.pfnServerPrint( text ); - - const char *temp; - if ( teamonly ) - temp = "say_team"; - else - temp = "say"; - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pEntity ), "model" ), - temp, - p ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" %s \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - temp, - p ); - } -} - - -/* -=========== -ClientCommand -called each time a player uses a "cmd" command -============ -*/ -extern float g_flWeaponCheat; - -// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command. -void ClientCommand( edict_t *pEntity ) -{ - const char *pcmd = CMD_ARGV(0); - const char *pstr; - - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - entvars_t *pev = &pEntity->v; - - if ( FStrEq(pcmd, "say" ) ) - { - Host_Say( pEntity, 0 ); - } - else if ( FStrEq(pcmd, "say_team" ) ) - { - Host_Say( pEntity, 1 ); - } - else if ( FStrEq(pcmd, "fullupdate" ) ) - { - GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); - } - else if ( FStrEq(pcmd, "give" ) ) - { - if ( g_flWeaponCheat != 0.0) - { - int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname - GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); - } - } - - else if ( FStrEq(pcmd, "drop" ) ) - { - // player is dropping an item. - GetClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1)); - } - else if ( FStrEq(pcmd, "fov" ) ) - { - if ( g_flWeaponCheat && CMD_ARGC() > 1) - { - GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) ); - } - else - { - CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) ); - } - } - else if ( FStrEq(pcmd, "use" ) ) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1)); - } - else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd)) - { - GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd); - } - else if (FStrEq(pcmd, "lastinv" )) - { - GetClassPtr((CBasePlayer *)pev)->SelectLastItem(); - } - else if ( FStrEq( pcmd, "spectate" ) ) // clients wants to become a spectator - { - // always allow proxies to become a spectator - if ( (pev->flags & FL_PROXY) || allow_spectators.value ) - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - - edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS(pentSpawnSpot)->angles); - - // notify other clients of player switching to spectator mode - UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s switched to spectator mode\n", - ( pev->netname && STRING(pev->netname)[0] != 0 ) ? STRING(pev->netname) : "unconnected" ) ); - } - else - ClientPrint( pev, HUD_PRINTCONSOLE, "Spectator mode is disabled.\n" ); - - } - else if ( FStrEq( pcmd, "specmode" ) ) // new spectator mode - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - - if ( pPlayer->IsObserver() ) - pPlayer->Observer_SetMode( atoi( CMD_ARGV(1) ) ); - } - else if ( FStrEq(pcmd, "closemenus" ) ) - { - // just ignore it - } - else if ( FStrEq( pcmd, "follownext" ) ) // follow next player - { - CBasePlayer * pPlayer = GetClassPtr((CBasePlayer *)pev); - - if ( pPlayer->IsObserver() ) - pPlayer->Observer_FindNextPlayer( atoi( CMD_ARGV(1) )?true:false ); - } - else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) ) - { - // MenuSelect returns true only if the command is properly handled, so don't print a warning - } - else - { - // tell the user they entered an unknown command - char command[128]; - - // check the length of the command (prevents crash) - // max total length is 192 ...and we're adding a string below ("Unknown command: %s\n") - strncpy( command, pcmd, 127 ); - command[127] = '\0'; - - // tell the user they entered an unknown command - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", command ) ); - } -} - - -/* -======================== -ClientUserInfoChanged - -called after the player changes -userinfo - gives dll a chance to modify it before -it gets sent into the rest of the engine. -======================== -*/ -void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) -{ - // Is the client spawned yet? - if ( !pEntity->pvPrivateData ) - return; - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) - { - char sName[256]; - char *pName = g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ); - strncpy( sName, pName, sizeof(sName) - 1 ); - sName[ sizeof(sName) - 1 ] = '\0'; - - // First parse the name and remove any %'s - for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ ) - { - // Replace it with a space - if ( *pApersand == '%' ) - *pApersand = ' '; - } - - // Set the name - g_engfuncs.pfnSetClientKeyValue( ENTINDEX(pEntity), infobuffer, "name", sName ); - - if (gpGlobals->maxClients > 1) - { - char text[256]; - sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX(pEntity) ); - WRITE_STRING( text ); - MESSAGE_END(); - } - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" changed name to \"%s\"\n", - STRING( pEntity->v.netname ), - GETPLAYERUSERID( pEntity ), - GETPLAYERAUTHID( pEntity ), - GETPLAYERUSERID( pEntity ), - g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } - } - - g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer ); -} - -static int g_serveractive = 0; - -void ServerDeactivate( void ) -{ - // It's possible that the engine will call this function more times than is necessary - // Therefore, only run it one time for each call to ServerActivate - if ( g_serveractive != 1 ) - { - return; - } - - g_serveractive = 0; - - // Peform any shutdown operations here... - // -} - -void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) -{ - int i; - CBaseEntity *pClass; - - // Every call to ServerActivate should be matched by a call to ServerDeactivate - g_serveractive = 1; - - // Clients have not been initialized yet - for ( i = 0; i < edictCount; i++ ) - { - if ( pEdictList[i].free ) - continue; - - // Clients aren't necessarily initialized until ClientPutInServer() - if ( i < clientMax || !pEdictList[i].pvPrivateData ) - continue; - - pClass = CBaseEntity::Instance( &pEdictList[i] ); - // Activate this entity if it's got a class & isn't dormant - if ( pClass && !(pClass->pev->flags & FL_DORMANT) ) - { - pClass->Activate(); - } - else - { - ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) ); - } - } - - // Link user messages here to make sure first client can get them... - LinkUserMessages(); -} - - -/* -================ -PlayerPreThink - -Called every frame before physics are run -================ -*/ -void PlayerPreThink( edict_t *pEntity ) -{ - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PreThink( ); -} - -/* -================ -PlayerPostThink - -Called every frame after physics are run -================ -*/ -void PlayerPostThink( edict_t *pEntity ) -{ - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->PostThink( ); -} - - - -void ParmsNewLevel( void ) -{ -} - - -void ParmsChangeLevel( void ) -{ - // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - - if ( pSaveData ) - pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); -} - - -// -// GLOBALS ASSUMED SET: g_ulFrameCount -// -void StartFrame( void ) -{ - if ( g_pGameRules ) - g_pGameRules->Think(); - - if ( g_fGameOver ) - return; - - gpGlobals->teamplay = teamplay.value; - g_ulFrameCount++; -} - - -void ClientPrecache( void ) -{ - // setup precaches always needed - PRECACHE_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha - - // PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound - - PRECACHE_SOUND("player/pl_fallpain2.wav"); - PRECACHE_SOUND("player/pl_fallpain3.wav"); - - PRECACHE_SOUND("player/pl_step1.wav"); // walk on concrete - PRECACHE_SOUND("player/pl_step2.wav"); - PRECACHE_SOUND("player/pl_step3.wav"); - PRECACHE_SOUND("player/pl_step4.wav"); - - PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete - PRECACHE_SOUND("common/npc_step2.wav"); - PRECACHE_SOUND("common/npc_step3.wav"); - PRECACHE_SOUND("common/npc_step4.wav"); - - PRECACHE_SOUND("player/pl_metal1.wav"); // walk on metal - PRECACHE_SOUND("player/pl_metal2.wav"); - PRECACHE_SOUND("player/pl_metal3.wav"); - PRECACHE_SOUND("player/pl_metal4.wav"); - - PRECACHE_SOUND("player/pl_dirt1.wav"); // walk on dirt - PRECACHE_SOUND("player/pl_dirt2.wav"); - PRECACHE_SOUND("player/pl_dirt3.wav"); - PRECACHE_SOUND("player/pl_dirt4.wav"); - - PRECACHE_SOUND("player/pl_duct1.wav"); // walk in duct - PRECACHE_SOUND("player/pl_duct2.wav"); - PRECACHE_SOUND("player/pl_duct3.wav"); - PRECACHE_SOUND("player/pl_duct4.wav"); - - PRECACHE_SOUND("player/pl_grate1.wav"); // walk on grate - PRECACHE_SOUND("player/pl_grate2.wav"); - PRECACHE_SOUND("player/pl_grate3.wav"); - PRECACHE_SOUND("player/pl_grate4.wav"); - - PRECACHE_SOUND("player/pl_slosh1.wav"); // walk in shallow water - PRECACHE_SOUND("player/pl_slosh2.wav"); - PRECACHE_SOUND("player/pl_slosh3.wav"); - PRECACHE_SOUND("player/pl_slosh4.wav"); - - PRECACHE_SOUND("player/pl_tile1.wav"); // walk on tile - PRECACHE_SOUND("player/pl_tile2.wav"); - PRECACHE_SOUND("player/pl_tile3.wav"); - PRECACHE_SOUND("player/pl_tile4.wav"); - PRECACHE_SOUND("player/pl_tile5.wav"); - - PRECACHE_SOUND("player/pl_swim1.wav"); // breathe bubbles - PRECACHE_SOUND("player/pl_swim2.wav"); - PRECACHE_SOUND("player/pl_swim3.wav"); - PRECACHE_SOUND("player/pl_swim4.wav"); - - PRECACHE_SOUND("player/pl_ladder1.wav"); // climb ladder rung - PRECACHE_SOUND("player/pl_ladder2.wav"); - PRECACHE_SOUND("player/pl_ladder3.wav"); - PRECACHE_SOUND("player/pl_ladder4.wav"); - - PRECACHE_SOUND("player/pl_wade1.wav"); // wade in water - PRECACHE_SOUND("player/pl_wade2.wav"); - PRECACHE_SOUND("player/pl_wade3.wav"); - PRECACHE_SOUND("player/pl_wade4.wav"); - - PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture - PRECACHE_SOUND("debris/wood2.wav"); - PRECACHE_SOUND("debris/wood3.wav"); - - PRECACHE_SOUND("plats/train_use1.wav"); // use a train - - PRECACHE_SOUND("buttons/spark5.wav"); // hit computer texture - PRECACHE_SOUND("buttons/spark6.wav"); - PRECACHE_SOUND("debris/glass1.wav"); - PRECACHE_SOUND("debris/glass2.wav"); - PRECACHE_SOUND("debris/glass3.wav"); - - PRECACHE_SOUND( SOUND_FLASHLIGHT_ON ); - PRECACHE_SOUND( SOUND_FLASHLIGHT_OFF ); - -// player gib sounds - PRECACHE_SOUND("common/bodysplat.wav"); - -// player pain sounds - PRECACHE_SOUND("player/pl_pain2.wav"); - PRECACHE_SOUND("player/pl_pain4.wav"); - PRECACHE_SOUND("player/pl_pain5.wav"); - PRECACHE_SOUND("player/pl_pain6.wav"); - PRECACHE_SOUND("player/pl_pain7.wav"); - - PRECACHE_MODEL("models/player.mdl"); - - // hud sounds - - PRECACHE_SOUND("common/wpn_hudoff.wav"); - PRECACHE_SOUND("common/wpn_hudon.wav"); - PRECACHE_SOUND("common/wpn_moveselect.wav"); - PRECACHE_SOUND("common/wpn_select.wav"); - PRECACHE_SOUND("common/wpn_denyselect.wav"); - - - // geiger sounds - - PRECACHE_SOUND("player/geiger6.wav"); - PRECACHE_SOUND("player/geiger5.wav"); - PRECACHE_SOUND("player/geiger4.wav"); - PRECACHE_SOUND("player/geiger3.wav"); - PRECACHE_SOUND("player/geiger2.wav"); - PRECACHE_SOUND("player/geiger1.wav"); - - if (giPrecacheGrunt) - UTIL_PrecacheOther("monster_human_grunt"); -} - -/* -=============== -GetGameDescription - -Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2 -=============== -*/ -const char *GetGameDescription() -{ - if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized - return g_pGameRules->GetGameDescription(); - else - return "Half-Life"; -} - -/* -================ -Sys_Error - -Engine is going to shut down, allows setting a breakpoint in game .dll to catch that occasion -================ -*/ -void Sys_Error( const char *error_string ) -{ - // Default case, do nothing. MOD AUTHORS: Add code ( e.g., _asm { int 3 }; here to cause a breakpoint for debugging your game .dlls -} - -/* -================ -PlayerCustomization - -A new player customization has been registered on the server -UNDONE: This only sets the # of frames of the spray can logo -animation right now. -================ -*/ -void PlayerCustomization( edict_t *pEntity, customization_t *pCust ) -{ - CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity); - - if (!pPlayer) - { - ALERT(at_console, "PlayerCustomization: Couldn't get player!\n"); - return; - } - - if (!pCust) - { - ALERT(at_console, "PlayerCustomization: NULL customization!\n"); - return; - } - - switch (pCust->resource.type) - { - case t_decal: - pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames. - break; - case t_sound: - case t_skin: - case t_model: - // Ignore for now. - break; - default: - ALERT(at_console, "PlayerCustomization: Unknown customization type!\n"); - break; - } -} - -/* -================ -SpectatorConnect - -A spectator has joined the game -================ -*/ -void SpectatorConnect( edict_t *pEntity ) -{ - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorConnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has left the game -================ -*/ -void SpectatorDisconnect( edict_t *pEntity ) -{ - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorDisconnect( ); -} - -/* -================ -SpectatorConnect - -A spectator has sent a usercmd -================ -*/ -void SpectatorThink( edict_t *pEntity ) -{ - CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity); - - if (pPlayer) - pPlayer->SpectatorThink( ); -} - -//////////////////////////////////////////////////////// -// PAS and PVS routines for client messaging -// - -/* -================ -SetupVisibility - -A client can have a separate "view entity" indicating that his/her view should depend on the origin of that -view entity. If that's the case, then pViewEntity will be non-NULL and will be used. Otherwise, the current -entity's origin is used. Either is offset by the view_ofs to get the eye position. - -From the eye position, we set up the PAS and PVS to use for filtering network messages to the client. At this point, we could - override the actual PAS or PVS values, or use a different origin. - -NOTE: Do not cache the values of pas and pvs, as they depend on reusable memory in the engine, they are only good for this one frame -================ -*/ -void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ) -{ - Vector org; - edict_t *pView = pClient; - - // Find the client's PVS - if ( pViewEntity ) - { - pView = pViewEntity; - } - - if ( pClient->v.flags & FL_PROXY ) - { - *pvs = NULL; // the spectator proxy sees - *pas = NULL; // and hears everything - return; - } - - org = pView->v.origin + pView->v.view_ofs; - if ( pView->v.flags & FL_DUCKING ) - { - org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - *pvs = ENGINE_SET_PVS ( (float *)&org ); - *pas = ENGINE_SET_PAS ( (float *)&org ); -} - -#include "entity_state.h" - -/* -AddToFullPack - -Return 1 if the entity state has been filled in for the ent and the entity will be propagated to the client, 0 otherwise - -state is the server maintained copy of the state info that is transmitted to the client -a MOD could alter values copied into state to send the "host" a different look for a particular entity update, etc. -e and ent are the entity that is being added to the update, if 1 is returned -host is the player's edict of the player whom we are sending the update to -player is 1 if the ent/e is a player and 0 otherwise -pSet is either the PAS or PVS that we previous set up. We can use it to ask the engine to filter the entity against the PAS or PVS. -we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. Caching the value is valid in that case, but still only for the current frame -*/ -int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) -{ - int i; - - // don't send if flagged for NODRAW and it's not the host getting the message - if ( ( ent->v.effects & EF_NODRAW ) && - ( ent != host ) ) - return 0; - - // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model ) ) - return 0; - - // Don't send spectators to other players - if ( ( ent->v.flags & FL_SPECTATOR ) && ( ent != host ) ) - { - return 0; - } - - // Ignore if not the host and not touching a PVS/PAS leaf - // If pSet is NULL, then the test will always succeed and the entity will be added to the update - if ( ent != host ) - { - if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) - { - return 0; - } - } - - - // Don't send entity to local client if the client says it's predicting the entity itself. - if ( ent->v.flags & FL_SKIPLOCALHOST ) - { - if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) - return 0; - } - - if ( host->v.groupinfo ) - { - UTIL_SetGroupTrace( host->v.groupinfo, GROUP_OP_AND ); - - // Should always be set, of course - if ( ent->v.groupinfo ) - { - if ( g_groupop == GROUP_OP_AND ) - { - if ( !(ent->v.groupinfo & host->v.groupinfo ) ) - return 0; - } - else if ( g_groupop == GROUP_OP_NAND ) - { - if ( ent->v.groupinfo & host->v.groupinfo ) - return 0; - } - } - - UTIL_UnsetGroupTrace(); - } - - memset( state, 0, sizeof( *state ) ); - - // Assign index so we can track this entity from frame to frame and - // delta from it. - state->number = e; - state->entityType = ENTITY_NORMAL; - - // Flag custom entities. - if ( ent->v.flags & FL_CUSTOMENTITY ) - { - state->entityType = ENTITY_BEAM; - } - - // - // Copy state data - // - - // Round animtime to nearest millisecond - state->animtime = (int)(1000.0 * ent->v.animtime ) / 1000.0; - - memcpy( state->origin, ent->v.origin, 3 * sizeof( float ) ); - memcpy( state->angles, ent->v.angles, 3 * sizeof( float ) ); - memcpy( state->mins, ent->v.mins, 3 * sizeof( float ) ); - memcpy( state->maxs, ent->v.maxs, 3 * sizeof( float ) ); - - memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); - memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); - - state->impacttime = ent->v.impacttime; - state->starttime = ent->v.starttime; - - state->modelindex = ent->v.modelindex; - - state->frame = ent->v.frame; - - state->skin = ent->v.skin; - state->effects = ent->v.effects; - - // This non-player entity is being moved by the game .dll and not the physics simulation system - // make sure that we interpolate it's position on the client if it moves - if ( !player && - ent->v.animtime && - ent->v.velocity[ 0 ] == 0 && - ent->v.velocity[ 1 ] == 0 && - ent->v.velocity[ 2 ] == 0 ) - { - state->eflags |= EFLAG_SLERP; - } - - state->scale = ent->v.scale; - state->solid = ent->v.solid; - state->colormap = ent->v.colormap; - - state->movetype = ent->v.movetype; - state->sequence = ent->v.sequence; - state->framerate = ent->v.framerate; - state->body = ent->v.body; - - for (i = 0; i < 4; i++) - { - state->controller[i] = ent->v.controller[i]; - } - - for (i = 0; i < 2; i++) - { - state->blending[i] = ent->v.blending[i]; - } - - state->rendermode = ent->v.rendermode; - state->renderamt = static_cast(ent->v.renderamt); - state->renderfx = ent->v.renderfx; - state->rendercolor.r = static_cast(ent->v.rendercolor.x); - state->rendercolor.g = static_cast(ent->v.rendercolor.y); - state->rendercolor.b = static_cast(ent->v.rendercolor.z); - - state->aiment = 0; - if ( ent->v.aiment ) - { - state->aiment = ENTINDEX( ent->v.aiment ); - } - - state->owner = 0; - if ( ent->v.owner ) - { - int owner = ENTINDEX( ent->v.owner ); - - // Only care if owned by a player - if ( owner >= 1 && owner <= gpGlobals->maxClients ) - { - state->owner = owner; - } - } - - // HACK: Somewhat... - // Class is overridden for non-players to signify a breakable glass object ( sort of a class? ) - if ( !player ) - { - state->playerclass = ent->v.playerclass; - } - - // Special stuff for players only - if ( player ) - { - memcpy( state->basevelocity, ent->v.basevelocity, 3 * sizeof( float ) ); - - state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); - state->gaitsequence = ent->v.gaitsequence; - state->spectator = ent->v.flags & FL_SPECTATOR; - state->friction = ent->v.friction; - - state->gravity = ent->v.gravity; -// state->team = ent->v.team; -// - state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; - state->health = static_cast(ent->v.health); - } - - return 1; -} - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 - -/* -=================== -CreateBaseline - -Creates baselines used for network encoding, especially for player data since players are not spawned until connect time. -=================== -*/ -void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ) -{ - baseline->origin = entity->v.origin; - baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; - - // render information - baseline->rendermode = (byte)entity->v.rendermode; - baseline->renderamt = (byte)entity->v.renderamt; - baseline->rendercolor.r = (byte)entity->v.rendercolor.x; - baseline->rendercolor.g = (byte)entity->v.rendercolor.y; - baseline->rendercolor.b = (byte)entity->v.rendercolor.z; - baseline->renderfx = (byte)entity->v.renderfx; - - if ( player ) - { - baseline->mins = player_mins; - baseline->maxs = player_maxs; - - baseline->colormap = eindex; - baseline->modelindex = playermodelindex; - baseline->friction = 1.0; - baseline->movetype = MOVETYPE_WALK; - - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; - baseline->framerate = 1.0; - baseline->gravity = 1.0; - - } - else - { - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; - - baseline->colormap = 0; - baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); - baseline->movetype = entity->v.movetype; - - baseline->scale = entity->v.scale; - baseline->solid = entity->v.solid; - baseline->framerate = entity->v.framerate; - baseline->gravity = entity->v.gravity; - } -} - -typedef struct -{ - char name[32]; - int field; -} entity_field_alias_t; - -#define FIELD_ORIGIN0 0 -#define FIELD_ORIGIN1 1 -#define FIELD_ORIGIN2 2 -#define FIELD_ANGLES0 3 -#define FIELD_ANGLES1 4 -#define FIELD_ANGLES2 5 - -static entity_field_alias_t entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, -}; - -void Entity_FieldInit( struct delta_s *pFields ) -{ - entity_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN0 ].name ); - entity_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN1 ].name ); - entity_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ORIGIN2 ].name ); - entity_field_alias[ FIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES0 ].name ); - entity_field_alias[ FIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES1 ].name ); - entity_field_alias[ FIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, entity_field_alias[ FIELD_ANGLES2 ].name ); -} - -/* -================== -Entity_Encode - -Callback for sending entity_state_t info over network. -FIXME: Move to script -================== -*/ -void Entity_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->impacttime != 0 ) && ( t->starttime != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ANGLES2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -static entity_field_alias_t player_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, -}; - -void Player_FieldInit( struct delta_s *pFields ) -{ - player_field_alias[ FIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN0 ].name ); - player_field_alias[ FIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN1 ].name ); - player_field_alias[ FIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, player_field_alias[ FIELD_ORIGIN2 ].name ); -} - -/* -================== -Player_Encode - -Callback for sending entity_state_t for players info over network. -================== -*/ -void Player_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int localplayer = 0; - static int initialized = 0; - - if ( !initialized ) - { - Player_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - // Never send origin to local player, it's sent with more resolution in clientdata_t structure - localplayer = ( t->number - 1 ) == ENGINE_CURRENT_PLAYER(); - if ( localplayer ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - - if ( ( t->movetype == MOVETYPE_FOLLOW ) && - ( t->aiment != 0 ) ) - { - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } - else if ( t->aiment != f->aiment ) - { - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN0 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN1 ].field ); - DELTA_SETBYINDEX( pFields, entity_field_alias[ FIELD_ORIGIN2 ].field ); - } -} - -#define CUSTOMFIELD_ORIGIN0 0 -#define CUSTOMFIELD_ORIGIN1 1 -#define CUSTOMFIELD_ORIGIN2 2 -#define CUSTOMFIELD_ANGLES0 3 -#define CUSTOMFIELD_ANGLES1 4 -#define CUSTOMFIELD_ANGLES2 5 -#define CUSTOMFIELD_SKIN 6 -#define CUSTOMFIELD_SEQUENCE 7 -#define CUSTOMFIELD_ANIMTIME 8 - -entity_field_alias_t custom_entity_field_alias[]= -{ - { "origin[0]", 0 }, - { "origin[1]", 0 }, - { "origin[2]", 0 }, - { "angles[0]", 0 }, - { "angles[1]", 0 }, - { "angles[2]", 0 }, - { "skin", 0 }, - { "sequence", 0 }, - { "animtime", 0 }, -}; - -void Custom_Entity_FieldInit( struct delta_s *pFields ) -{ - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field = DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].name ); - custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].name ); - custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field= DELTA_FINDFIELD( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].name ); -} - -/* -================== -Custom_Encode - -Callback for sending entity_state_t info ( for custom entities ) over network. -FIXME: Move to script -================== -*/ -void Custom_Encode( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) -{ - entity_state_t *f, *t; - int beamType; - static int initialized = 0; - - if ( !initialized ) - { - Custom_Entity_FieldInit( pFields ); - initialized = 1; - } - - f = (entity_state_t *)from; - t = (entity_state_t *)to; - - beamType = t->rendermode & 0x0f; - - if ( beamType != BEAM_POINTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ORIGIN2 ].field ); - } - - if ( beamType != BEAM_POINTS ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES0 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES1 ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANGLES2 ].field ); - } - - if ( beamType != BEAM_ENTS && beamType != BEAM_ENTPOINT ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SKIN ].field ); - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_SEQUENCE ].field ); - } - - // animtime is compared by rounding first - // see if we really shouldn't actually send it - if ( (int)f->animtime == (int)t->animtime ) - { - DELTA_UNSETBYINDEX( pFields, custom_entity_field_alias[ CUSTOMFIELD_ANIMTIME ].field ); - } -} - -/* -================= -RegisterEncoders - -Allows game .dll to override network encoding of certain types of entities and tweak values, etc. -================= -*/ -void RegisterEncoders( void ) -{ - DELTA_ADDENCODER( "Entity_Encode", Entity_Encode ); - DELTA_ADDENCODER( "Custom_Encode", Custom_Encode ); - DELTA_ADDENCODER( "Player_Encode", Player_Encode ); -} - -int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) -{ -#if defined( CLIENT_WEAPONS ) - int i; - weapon_data_t *item; - entvars_t *pev = &player->v; - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); - CBasePlayerWeapon *gun; - - ItemInfo II; - - memset( info, 0, 32 * sizeof( weapon_data_t ) ); - - if ( !pl ) - return 1; - - // go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( pl->m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = pl->m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - gun = dynamic_cast( pPlayerItem->GetWeaponPtr() ); - if ( gun && gun->UseDecrement() ) - { - // Get The ID. - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - if ( II.iId >= 0 && II.iId < 32 ) - { - item = &info[ II.iId ]; - - item->m_iId = II.iId; - item->m_iClip = gun->m_iClip; - - item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 ); - item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 ); - item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001 ); - item->m_fInReload = gun->m_fInReload; - item->m_fInSpecialReload = gun->m_fInSpecialReload; - item->fuser1 = max( gun->pev->fuser1, -0.001 ); - item->fuser2 = gun->m_flStartThrow; - item->fuser3 = gun->m_flReleaseThrow; - item->iuser1 = gun->m_chargeReady; - item->iuser2 = gun->m_fInAttack; - item->iuser3 = gun->m_fireState; - - -// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); - } - } - pPlayerItem = pPlayerItem->m_pNext; - } - } - } -#else - memset( info, 0, 32 * sizeof( weapon_data_t ) ); -#endif - return 1; -} - -/* -================= -UpdateClientData - -Data sent to current client only -engine sets cd to 0 before calling. -================= -*/ -void UpdateClientData ( const edict_t *ent, int sendweapons, struct clientdata_s *cd ) -{ - if ( !ent || !ent->pvPrivateData ) - return; - entvars_t * pev = (entvars_t *)&ent->v; - CBasePlayer * pl = dynamic_cast< CBasePlayer *>(CBasePlayer::Instance( pev )); - entvars_t * pevOrg = NULL; - - // if user is spectating different player in First person, override some vars - if ( pl && pl->pev->iuser1 == OBS_IN_EYE ) - { - if ( pl->m_hObserverTarget ) - { - pevOrg = pev; - pev = pl->m_hObserverTarget->pev; - pl = dynamic_cast< CBasePlayer *>(CBasePlayer::Instance( pev ) ); - } - } - - cd->flags = pev->flags; - cd->health = pev->health; - - cd->viewmodel = MODEL_INDEX( STRING( pev->viewmodel ) ); - - cd->waterlevel = pev->waterlevel; - cd->watertype = pev->watertype; - cd->weapons = pev->weapons; - - // Vectors - cd->origin = pev->origin; - cd->velocity = pev->velocity; - cd->view_ofs = pev->view_ofs; - cd->punchangle = pev->punchangle; - - cd->bInDuck = pev->bInDuck; - cd->flTimeStepSound = pev->flTimeStepSound; - cd->flDuckTime = pev->flDuckTime; - cd->flSwimTime = pev->flSwimTime; - cd->waterjumptime = pev->teleport_time; - - strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - - cd->maxspeed = pev->maxspeed; - cd->fov = pev->fov; - cd->weaponanim = pev->weaponanim; - - cd->pushmsec = pev->pushmsec; - - //Spectator mode - if ( pevOrg != NULL ) - { - // don't use spec vars from chased player - cd->iuser1 = pevOrg->iuser1; - cd->iuser2 = pevOrg->iuser2; - } - else - { - cd->iuser1 = pev->iuser1; - cd->iuser2 = pev->iuser2; - } - - - -#if defined( CLIENT_WEAPONS ) - if ( sendweapons ) - { - if ( pl ) - { - cd->m_flNextAttack = pl->m_flNextAttack; - cd->fuser2 = pl->m_flNextAmmoBurn; - cd->fuser3 = pl->m_flAmmoStartCharge; - cd->vuser1.x = pl->ammo_9mm; - cd->vuser1.y = pl->ammo_357; - cd->vuser1.z = pl->ammo_argrens; - cd->ammo_nails = pl->ammo_bolts; - cd->ammo_shells = pl->ammo_buckshot; - cd->ammo_rockets = pl->ammo_rockets; - cd->ammo_cells = pl->ammo_uranium; - cd->vuser2.x = pl->ammo_hornets; - - - if ( pl->m_pActiveItem ) - { - CBasePlayerWeapon *gun; - gun = (CBasePlayerWeapon *)pl->m_pActiveItem->GetWeaponPtr(); - if ( gun && gun->UseDecrement() ) - { - ItemInfo II; - memset( &II, 0, sizeof( II ) ); - gun->GetItemInfo( &II ); - - cd->m_iId = II.iId; - - cd->vuser3.z = gun->m_iSecondaryAmmoType; - cd->vuser4.x = gun->m_iPrimaryAmmoType; - cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; - cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; - - if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) - { - cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; - cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; - } - } - } - } - } -#endif -} - -/* -================= -CmdStart - -We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc. -This is the time to examine the usercmd for anything extra. This call happens even if think does not. -================= -*/ -void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ) -{ - entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); - - if( !pl ) - return; - - if ( pl->pev->groupinfo != 0 ) - { - UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); - } - - pl->random_seed = random_seed; -} - -/* -================= -CmdEnd - -Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here -================= -*/ -void CmdEnd ( const edict_t *player ) -{ - entvars_t *pev = (entvars_t *)&player->v; - CBasePlayer *pl = dynamic_cast< CBasePlayer *>( CBasePlayer::Instance( pev ) ); - - if( !pl ) - return; - if ( pl->pev->groupinfo != 0 ) - { - UTIL_UnsetGroupTrace(); - } -} - -/* -================================ -ConnectionlessPacket - - Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max - size of the response_buffer, so you must zero it out if you choose not to respond. -================================ -*/ -int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) -{ - // Zero it out since we aren't going to respond. - // If we wanted to response, we'd write data into response_buffer - *response_buffer_size = 0; - - // Since we don't listen for anything here, just respond that it's a bogus message - // If we didn't reject the message, we'd return 1 for success instead. - return 0; -} - -/* -================================ -GetHullBounds - - Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. -================================ -*/ -int GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch ( hullnumber ) - { - case 0: // Normal player - mins = VEC_HULL_MIN; - maxs = VEC_HULL_MAX; - iret = 1; - break; - case 1: // Crouched player - mins = VEC_DUCK_HULL_MIN; - maxs = VEC_DUCK_HULL_MAX; - iret = 1; - break; - case 2: // Point based hull - mins = Vector( 0, 0, 0 ); - maxs = Vector( 0, 0, 0 ); - iret = 1; - break; - } - - return iret; -} - -/* -================================ -CreateInstancedBaselines - -Create pseudo-baselines for items that aren't placed in the map at spawn time, but which are likely -to be created during play ( e.g., grenades, ammo packs, projectiles, corpses, etc. ) -================================ -*/ -void CreateInstancedBaselines ( void ) -{ - entity_state_t state; - - memset( &state, 0, sizeof( state ) ); - - // Create any additional baselines here for things like grendates, etc. - // iret = ENGINE_INSTANCE_BASELINE( pc->pev->classname, &state ); - - // Destroy objects. - //UTIL_Remove( pc ); -} - -/* -================================ -InconsistentFile - -One of the ENGINE_FORCE_UNMODIFIED files failed the consistency check for the specified player - Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) -================================ -*/ -int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ) -{ - // Server doesn't care? - if ( CVAR_GET_FLOAT( "mp_consistency" ) != 1 ) - return 0; - - // Default behavior is to kick the player - sprintf( disconnect_message, "Server is enforcing file consistency for %s\n", filename ); - - // Kick now with specified disconnect message. - return 1; -} - -/* -================================ -AllowLagCompensation - - The game .dll should return 1 if lag compensation should be allowed ( could also just set - the sv_unlag cvar. - Most games right now should return 0, until client-side weapon prediction code is written - and tested for them ( note you can predict weapons, but not do lag compensation, too, - if you want. -================================ -*/ -int AllowLagCompensation( void ) -{ - return 1; -} diff --git a/sdk/dlls/client.h b/sdk/dlls/client.h deleted file mode 100644 index 1e66cc8..0000000 --- a/sdk/dlls/client.h +++ /dev/null @@ -1,65 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef CLIENT_H -#define CLIENT_H - -extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); -extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); -extern void ClientDisconnect( edict_t *pEntity ); -extern void ClientKill( edict_t *pEntity ); -extern void ClientPutInServer( edict_t *pEntity ); -extern void ClientCommand( edict_t *pEntity ); -extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); -extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); -extern void ServerDeactivate( void ); -extern void StartFrame( void ); -extern void PlayerPostThink( edict_t *pEntity ); -extern void PlayerPreThink( edict_t *pEntity ); -extern void ParmsNewLevel( void ); -extern void ParmsChangeLevel( void ); - -extern void ClientPrecache( void ); - -extern const char *GetGameDescription( void ); -extern void PlayerCustomization( edict_t *pEntity, customization_t *pCust ); - -extern void SpectatorConnect ( edict_t *pEntity ); -extern void SpectatorDisconnect ( edict_t *pEntity ); -extern void SpectatorThink ( edict_t *pEntity ); - -extern void Sys_Error( const char *error_string ); - -extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); -extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); -extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); -extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); -extern void RegisterEncoders( void ); - -extern int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ); - -extern void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); -extern void CmdEnd ( const edict_t *player ); - -extern int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); - -extern int GetHullBounds( int hullnumber, float *mins, float *maxs ); - -extern void CreateInstancedBaselines ( void ); - -extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); - -extern int AllowLagCompensation( void ); - -#endif // CLIENT_H diff --git a/sdk/dlls/combat.cpp b/sdk/dlls/combat.cpp deleted file mode 100644 index c2a51ba..0000000 --- a/sdk/dlls/combat.cpp +++ /dev/null @@ -1,1701 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== combat.cpp ======================================================== - - functions dealing with damage infliction & death - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" -#include "decals.h" -#include "animation.h" -#include "weapons.h" -#include "func_break.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL int g_iSkillLevel; - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern entvars_t *g_pevLastInflictor; - -#define GERMAN_GIB_COUNT 4 -#define HUMAN_GIB_COUNT 6 -#define ALIEN_GIB_COUNT 4 - - -// HACKHACK -- The gib velocity equations don't work -void CGib :: LimitVelocity( void ) -{ - float length = pev->velocity.Length(); - - // ceiling at 1500. The gib velocity equation is not bounded properly. Rather than tune it - // in 3 separate places again, I'll just limit it here. - if ( length > 1500.0 ) - pev->velocity = pev->velocity.Normalize() * 1500; // This should really be sv_maxvelocity * 0.75 or something -} - - -void CGib :: SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ) -{ - int i; - - if ( g_Language == LANGUAGE_GERMAN ) - { - // no sticky gibs in germany right now! - return; - } - - for ( i = 0 ; i < cGibs ; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( "models/stickygib.mdl" ); - pGib->pev->body = RANDOM_LONG(0,2); - - if ( pevVictim ) - { - pGib->pev->origin.x = vecOrigin.x + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.y = vecOrigin.y + RANDOM_FLOAT( -3, 3 ); - pGib->pev->origin.z = vecOrigin.z + RANDOM_FLOAT( -3, 3 ); - - /* - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ); - */ - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.15, 0.15 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.15, 0.15 ); - - pGib->pev->velocity = pGib->pev->velocity * 900; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 250, 400 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 250, 400 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - - pGib->pev->movetype = MOVETYPE_TOSS; - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector ( 0, 0 ,0 ), Vector ( 0, 0, 0 ) ); - pGib->SetTouch ( &CGib::StickyGibTouch ); - pGib->SetThink (NULL); - } - pGib->LimitVelocity(); - } -} - -void CGib :: SpawnHeadGib( entvars_t *pevVictim ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" );// throw one head - pGib->pev->body = 0; - } - else - { - pGib->Spawn( "models/hgibs.mdl" );// throw one head - pGib->pev->body = 0; - } - - if ( pevVictim ) - { - pGib->pev->origin = pevVictim->origin + pevVictim->view_ofs; - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS( pGib->edict() ); - - if ( RANDOM_LONG ( 0, 100 ) <= 5 && pentPlayer ) - { - // 5% chance head will be thrown at player's face. - entvars_t *pevPlayer; - - pevPlayer = VARS( pentPlayer ); - pGib->pev->velocity = ( ( pevPlayer->origin + pevPlayer->view_ofs ) - pGib->pev->origin ).Normalize() * 300; - pGib->pev->velocity.z += 100; - } - else - { - pGib->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - } - - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - } - pGib->LimitVelocity(); -} - -void CGib :: SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ) -{ - int cSplat; - - for ( cSplat = 0 ; cSplat < cGibs ; cSplat++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - if ( g_Language == LANGUAGE_GERMAN ) - { - pGib->Spawn( "models/germangibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,GERMAN_GIB_COUNT-1); - } - else - { - if ( human ) - { - // human pieces - pGib->Spawn( "models/hgibs.mdl" ); - pGib->pev->body = RANDOM_LONG(1,HUMAN_GIB_COUNT-1);// start at one to avoid throwing random amounts of skulls (0th gib) - } - else - { - // aliens - pGib->Spawn( "models/agibs.mdl" ); - pGib->pev->body = RANDOM_LONG(0,ALIEN_GIB_COUNT-1); - } - } - - if ( pevVictim ) - { - // spawn the gib somewhere in the monster's bounding volume - pGib->pev->origin.x = pevVictim->absmin.x + pevVictim->size.x * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.y = pevVictim->absmin.y + pevVictim->size.y * (RANDOM_FLOAT ( 0 , 1 ) ); - pGib->pev->origin.z = pevVictim->absmin.z + pevVictim->size.z * (RANDOM_FLOAT ( 0 , 1 ) ) + 1; // absmin.z is in the floor because the engine subtracts 1 to enlarge the box - - // make the gib fly away from the attack vector - pGib->pev->velocity = g_vecAttackDir * -1; - - // mix in some noise - pGib->pev->velocity.x += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.y += RANDOM_FLOAT ( -0.25, 0.25 ); - pGib->pev->velocity.z += RANDOM_FLOAT ( -0.25, 0.25 ); - - pGib->pev->velocity = pGib->pev->velocity * RANDOM_FLOAT ( 300, 400 ); - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - // copy owner's blood color - pGib->m_bloodColor = (CBaseEntity::Instance(pevVictim))->BloodColor(); - - if ( pevVictim->health > -50) - { - pGib->pev->velocity = pGib->pev->velocity * 0.7; - } - else if ( pevVictim->health > -200) - { - pGib->pev->velocity = pGib->pev->velocity * 2; - } - else - { - pGib->pev->velocity = pGib->pev->velocity * 4; - } - - pGib->pev->solid = SOLID_BBOX; - UTIL_SetSize ( pGib->pev, Vector( 0 , 0 , 0 ), Vector ( 0, 0, 0 ) ); - } - pGib->LimitVelocity(); - } -} - - -BOOL CBaseMonster :: HasHumanGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_HUMAN_MILITARY || - myClass == CLASS_PLAYER_ALLY || - myClass == CLASS_HUMAN_PASSIVE || - myClass == CLASS_PLAYER ) - - return TRUE; - - return FALSE; -} - - -BOOL CBaseMonster :: HasAlienGibs( void ) -{ - int myClass = Classify(); - - if ( myClass == CLASS_ALIEN_MILITARY || - myClass == CLASS_ALIEN_MONSTER || - myClass == CLASS_ALIEN_PASSIVE || - myClass == CLASS_INSECT || - myClass == CLASS_ALIEN_PREDATOR || - myClass == CLASS_ALIEN_PREY ) - - return TRUE; - - return FALSE; -} - - -void CBaseMonster::FadeMonster( void ) -{ - StopAnimation(); - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; - pev->avelocity = g_vecZero; - pev->animtime = gpGlobals->time; - pev->effects |= EF_NOINTERP; - SUB_StartFadeOut(); -} - -//========================================================= -// GibMonster - create some gore and get rid of a monster's -// model. -//========================================================= -void CBaseMonster :: GibMonster( void ) -{ - TraceResult tr; - BOOL gibbed = FALSE; - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM); - - // only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs - if ( HasHumanGibs() ) - { - if ( CVAR_GET_FLOAT("violence_hgibs") != 0 ) // Only the player will ever get here - { - CGib::SpawnHeadGib( pev ); - CGib::SpawnRandomGibs( pev, 4, 1 ); // throw some human gibs. - } - gibbed = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( CVAR_GET_FLOAT("violence_agibs") != 0 ) // Should never get here, but someone might call it directly - { - CGib::SpawnRandomGibs( pev, 4, 0 ); // Throw alien gibs - } - gibbed = TRUE; - } - - if ( !IsPlayer() ) - { - if ( gibbed ) - { - // don't remove players! - SetThink ( &CBaseMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - else - { - FadeMonster(); - } - } -} - -//========================================================= -// GetDeathActivity - determines the best type of death -// anim to play. -//========================================================= -Activity CBaseMonster :: GetDeathActivity ( void ) -{ - Activity deathActivity; - BOOL fTriedDirection; - float flDot; - TraceResult tr; - Vector vecSrc; - - if ( pev->deadflag != DEAD_NO ) - { - // don't run this while dying. - return m_IdealActivity; - } - - vecSrc = Center(); - - fTriedDirection = FALSE; - deathActivity = ACT_DIESIMPLE;// in case we can't find any special deaths to do. - - UTIL_MakeVectors ( pev->angles ); - flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // try to pick a region-specific death. - case HITGROUP_HEAD: - deathActivity = ACT_DIE_HEADSHOT; - break; - - case HITGROUP_STOMACH: - deathActivity = ACT_DIE_GUTSHOT; - break; - - case HITGROUP_GENERIC: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - - default: - // try to pick a death based on attack direction - fTriedDirection = TRUE; - - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - break; - } - - - // can we perform the prescribed death? - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // no! did we fail to perform a directional death? - if ( fTriedDirection ) - { - // if yes, we're out of options. Go simple. - deathActivity = ACT_DIESIMPLE; - } - else - { - // cannot perform the ideal region-specific death, so try a direction. - if ( flDot > 0.3 ) - { - deathActivity = ACT_DIEFORWARD; - } - else if ( flDot <= -0.3 ) - { - deathActivity = ACT_DIEBACKWARD; - } - } - } - - if ( LookupActivity ( deathActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - // if we're still invalid, simple is our only option. - deathActivity = ACT_DIESIMPLE; - } - - if ( deathActivity == ACT_DIEFORWARD ) - { - // make sure there's room to fall forward - UTIL_TraceHull ( vecSrc, vecSrc + gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - if ( deathActivity == ACT_DIEBACKWARD ) - { - // make sure there's room to fall backward - UTIL_TraceHull ( vecSrc, vecSrc - gpGlobals->v_forward * 64, dont_ignore_monsters, head_hull, edict(), &tr ); - - if ( tr.flFraction != 1.0 ) - { - deathActivity = ACT_DIESIMPLE; - } - } - - return deathActivity; -} - -//========================================================= -// GetSmallFlinchActivity - determines the best type of flinch -// anim to play. -//========================================================= -Activity CBaseMonster :: GetSmallFlinchActivity ( void ) -{ - Activity flinchActivity; -// float flDot; - - UTIL_MakeVectors ( pev->angles ); -// flDot = DotProduct ( gpGlobals->v_forward, g_vecAttackDir * -1 ); - - switch ( m_LastHitGroup ) - { - // pick a region-specific flinch - case HITGROUP_HEAD: - flinchActivity = ACT_FLINCH_HEAD; - break; - case HITGROUP_STOMACH: - flinchActivity = ACT_FLINCH_STOMACH; - break; - case HITGROUP_LEFTARM: - flinchActivity = ACT_FLINCH_LEFTARM; - break; - case HITGROUP_RIGHTARM: - flinchActivity = ACT_FLINCH_RIGHTARM; - break; - case HITGROUP_LEFTLEG: - flinchActivity = ACT_FLINCH_LEFTLEG; - break; - case HITGROUP_RIGHTLEG: - flinchActivity = ACT_FLINCH_RIGHTLEG; - break; - case HITGROUP_GENERIC: - default: - // just get a generic flinch. - flinchActivity = ACT_SMALL_FLINCH; - break; - } - - - // do we have a sequence for the ideal activity? - if ( LookupActivity ( flinchActivity ) == ACTIVITY_NOT_AVAILABLE ) - { - flinchActivity = ACT_SMALL_FLINCH; - } - - return flinchActivity; -} - - -void CBaseMonster::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. - - // make the corpse fly away from the attack vector - pev->movetype = MOVETYPE_TOSS; - //pev->flags &= ~FL_ONGROUND; - //pev->origin.z += 2; - //pev->velocity = g_vecAttackDir * -1; - //pev->velocity = pev->velocity * RANDOM_FLOAT( 300, 400 ); -} - - -BOOL CBaseMonster::ShouldGibMonster( int iGib ) -{ - if ( ( iGib == GIB_NORMAL && pev->health < GIB_HEALTH_VALUE ) || ( iGib == GIB_ALWAYS ) ) - return TRUE; - - return FALSE; -} - - -void CBaseMonster::CallGibMonster( void ) -{ - BOOL fade = FALSE; - - if ( HasHumanGibs() ) - { - if ( CVAR_GET_FLOAT("violence_hgibs") == 0 ) - fade = TRUE; - } - else if ( HasAlienGibs() ) - { - if ( CVAR_GET_FLOAT("violence_agibs") == 0 ) - fade = TRUE; - } - - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT;// do something with the body. while monster blows up - - if ( fade ) - { - FadeMonster(); - } - else - { - pev->effects = EF_NODRAW; // make the model invisible. - GibMonster(); - } - - pev->deadflag = DEAD_DEAD; - FCheckAITrigger(); - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - if ( ShouldFadeOnDeath() && !fade ) - UTIL_Remove(this); -} - - -/* -============ -Killed -============ -*/ -void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - if ( HasMemory( bits_MEMORY_KILLED ) ) - { - if ( ShouldGibMonster( iGib ) ) - CallGibMonster(); - return; - } - - Remember( bits_MEMORY_KILLED ); - - // clear the deceased's sound channels.(may have been firing or reloading when killed) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "common/null.wav", 1, ATTN_NORM); - m_IdealMonsterState = MONSTERSTATE_DEAD; - // Make sure this condition is fired too (TakeDamage breaks out before this happens on death) - SetConditions( bits_COND_LIGHT_DAMAGE ); - - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - - if ( ShouldGibMonster( iGib ) ) - { - CallGibMonster(); - return; - } - else if ( pev->flags & FL_MONSTER ) - { - SetTouch( NULL ); - BecomeDead(); - } - - // don't let the status bar glitch for players.with <0 health. - if (pev->health < -99) - { - pev->health = 0; - } - - //pev->enemy = ENT( pevAttacker );//why? (sjb) - - m_IdealMonsterState = MONSTERSTATE_DEAD; -} - -// -// fade out - slowly fades a entity out, then removes it. -// -// DON'T USE ME FOR GIBS AND STUFF IN MULTIPLAYER! -// SET A FUTURE THINK AND A RENDERMODE!! -void CBaseEntity :: SUB_StartFadeOut ( void ) -{ - if (pev->rendermode == kRenderNormal) - { - pev->renderamt = 255; - pev->rendermode = kRenderTransTexture; - } - - pev->solid = SOLID_NOT; - pev->avelocity = g_vecZero; - - pev->nextthink = gpGlobals->time + 0.1; - SetThink ( &CBaseEntity::SUB_FadeOut ); -} - -void CBaseEntity :: SUB_FadeOut ( void ) -{ - if ( pev->renderamt > 7 ) - { - pev->renderamt -= 7; - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - pev->renderamt = 0; - pev->nextthink = gpGlobals->time + 0.2; - SetThink ( &CBaseEntity::SUB_Remove ); - } -} - -//========================================================= -// WaitTillLand - in order to emit their meaty scent from -// the proper location, gibs should wait until they stop -// bouncing to emit their scent. That's what this function -// does. -//========================================================= -void CGib :: WaitTillLand ( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if ( pev->velocity == g_vecZero ) - { - SetThink (&CGib::SUB_StartFadeOut); - pev->nextthink = gpGlobals->time + m_lifeTime; - - // If you bleed, you stink! - if ( m_bloodColor != DONT_BLEED ) - { - // ok, start stinkin! - CSoundEnt::InsertSound ( bits_SOUND_MEAT, pev->origin, 384, 25 ); - } - } - else - { - // wait and check again in another half second. - pev->nextthink = gpGlobals->time + 0.5; - } -} - -// -// Gib bounces on the ground or wall, sponges some blood down, too! -// -void CGib :: BounceGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - //if ( RANDOM_LONG(0,1) ) - // return;// don't bleed everytime - - if (pev->flags & FL_ONGROUND) - { - pev->velocity = pev->velocity * 0.9; - pev->angles.x = 0; - pev->angles.z = 0; - pev->avelocity.x = 0; - pev->avelocity.z = 0; - } - else - { - if ( g_Language != LANGUAGE_GERMAN && m_cBloodDecals > 0 && m_bloodColor != DONT_BLEED ) - { - vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - m_cBloodDecals--; - } - - if ( m_material != matNone && RANDOM_LONG(0,2) == 0 ) - { - float volume; - float zvel = fabs(pev->velocity.z); - - volume = 0.8 * min(1.0, ((float)zvel) / 450.0); - - CBreakable::MaterialSoundRandom( edict(), (Materials)m_material, volume ); - } - } -} - -// -// Sticky gib puts blood on the wall and stays put. -// -void CGib :: StickyGibTouch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - SetThink ( &CGib::SUB_Remove ); - pev->nextthink = gpGlobals->time + 10; - - if ( !FClassnameIs( pOther->pev, "worldspawn" ) ) - { - pev->nextthink = gpGlobals->time; - return; - } - - UTIL_TraceLine ( pev->origin, pev->origin + pev->velocity * 32, ignore_monsters, ENT(pev), & tr); - - UTIL_BloodDecalTrace( &tr, m_bloodColor ); - - pev->velocity = tr.vecPlaneNormal * -1; - pev->angles = UTIL_VecToAngles ( pev->velocity ); - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->movetype = MOVETYPE_NONE; -} - -// -// Throw a chunk -// -void CGib :: Spawn( const char *szGibModel ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->friction = 0.55; // deading the bounce a bit - - // sometimes an entity inherits the edict from a former piece of glass, - // and will spawn using the same render FX or rendermode! bad! - pev->renderamt = 255; - pev->rendermode = kRenderNormal; - pev->renderfx = kRenderFxNone; - pev->solid = SOLID_SLIDEBOX;/// hopefully this will fix the VELOCITY TOO LOW crap - pev->classname = MAKE_STRING("gib"); - - SET_MODEL(ENT(pev), szGibModel); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pev->nextthink = gpGlobals->time + 4; - m_lifeTime = 25; - SetThink ( &CGib::WaitTillLand ); - SetTouch ( &CGib::BounceGibTouch ); - - m_material = matNone; - m_cBloodDecals = 5;// how many blood decals this gib can place (1 per bounce until none remain). -} - -// take health -int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) -{ - if (!pev->takedamage) - return 0; - - // clear out any damage types we healed. - // UNDONE: generic health should not heal any - // UNDONE: time-based damage - - m_bitsDamageType &= ~(bitsDamageType & ~DMG_TIMEBASED); - - return CBaseEntity::TakeHealth(flHealth, bitsDamageType); -} - -/* -============ -TakeDamage - -The damage is coming from inflictor, but get mad at attacker -This should be the only function that ever reduces health. -bitsDamageType indicates the type of damage sustained, ie: DMG_SHOCK - -Time-based damage: only occurs while the monster is within the trigger_hurt. -When a monster is poisoned via an arrow etc it takes all the poison damage at once. - - - -GLOBALS ASSUMED SET: g_iSkillLevel -============ -*/ -int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - float flTake; - Vector vecDir; - - if (!pev->takedamage) - return 0; - - if ( !IsAlive() ) - { - return DeadTakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - } - - if ( pev->deadflag == DEAD_NO ) - { - // no pain sound during death animation. - PainSound();// "Ouch!" - } - - //!!!LATER - make armor consideration here! - flTake = flDamage; - - // set damage type sustained - m_bitsDamageType |= bitsDamageType; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - - // add to the damage total for clients, which will be sent as a single - // message at the end of the frame - // todo: remove after combining shotgun blasts? - if ( IsPlayer() ) - { - if ( pevInflictor ) - pev->dmg_inflictor = ENT(pevInflictor); - - pev->dmg_take += flTake; - - // check for godmode or invincibility - if ( pev->flags & FL_GODMODE ) - { - return 0; - } - } - - // if this is a player, move him around! - if ( ( !FNullEnt( pevInflictor ) ) && (pev->movetype == MOVETYPE_WALK) && (!pevAttacker || pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - - // do the damage - pev->health -= flTake; - - - // HACKHACK Don't kill monsters in a script. Let them break their scripts first - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - SetConditions( bits_COND_LIGHT_DAMAGE ); - return 0; - } - - if ( pev->health <= 0 ) - { - g_pevLastInflictor = pevInflictor; - - if ( bitsDamageType & DMG_ALWAYSGIB ) - { - Killed( pevAttacker, GIB_ALWAYS ); - } - else if ( bitsDamageType & DMG_NEVERGIB ) - { - Killed( pevAttacker, GIB_NEVER ); - } - else - { - Killed( pevAttacker, GIB_NORMAL ); - } - - g_pevLastInflictor = NULL; - - return 0; - } - - // react to the damage (get mad) - if ( (pev->flags & FL_MONSTER) && !FNullEnt(pevAttacker) ) - { - if ( pevAttacker->flags & (FL_MONSTER | FL_CLIENT) ) - {// only if the attack was a monster or client! - - // enemy's last known position is somewhere down the vector that the attack came from. - if (pevInflictor) - { - if (m_hEnemy == 0 || pevInflictor == m_hEnemy->pev || !HasConditions(bits_COND_SEE_ENEMY)) - { - m_vecEnemyLKP = pevInflictor->origin; - } - } - else - { - m_vecEnemyLKP = pev->origin + ( g_vecAttackDir * 64 ); - } - - MakeIdealYaw( m_vecEnemyLKP ); - - // add pain to the conditions - // !!!HACKHACK - fudged for now. Do we want to have a virtual function to determine what is light and - // heavy damage per monster class? - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - } - } - - return 1; -} - -//========================================================= -// DeadTakeDamage - takedamage function called when a monster's -// corpse is damaged. -//========================================================= -int CBaseMonster :: DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecDir; - - // grab the vector of the incoming attack. ( pretend that the inflictor is a little lower than it really is, so the body will tend to fly upward a bit). - vecDir = Vector( 0, 0, 0 ); - if (!FNullEnt( pevInflictor )) - { - CBaseEntity *pInflictor = CBaseEntity :: Instance( pevInflictor ); - if (pInflictor) - { - vecDir = ( pInflictor->Center() - Vector ( 0, 0, 10 ) - Center() ).Normalize(); - vecDir = g_vecAttackDir = vecDir.Normalize(); - } - } - -#if 0// turn this back on when the bounding box issues are resolved. - - pev->flags &= ~FL_ONGROUND; - pev->origin.z += 1; - - // let the damage scoot the corpse around a bit. - if ( !FNullEnt(pevInflictor) && (pevAttacker->solid != SOLID_TRIGGER) ) - { - pev->velocity = pev->velocity + vecDir * -DamageForce( flDamage ); - } - -#endif - - // kill the corpse if enough damage was done to destroy the corpse and the damage is of a type that is allowed to destroy the corpse. - if ( bitsDamageType & DMG_GIB_CORPSE ) - { - if ( pev->health <= flDamage ) - { - pev->health = -50; - Killed( pevAttacker, GIB_ALWAYS ); - return 0; - } - // Accumulate corpse gibbing damage, so you can gib with multiple hits - pev->health -= flDamage * 0.1; - } - - return 1; -} - - -float CBaseMonster :: DamageForce( float damage ) -{ - float force = damage * ((32 * 32 * 72.0) / (pev->size.x * pev->size.y * pev->size.z)) * 5; - - if ( force > 1000.0) - { - force = 1000.0; - } - - return force; -} - -// -// RadiusDamage - this entity is exploding, or otherwise needs to inflict damage upon entities within a certain range. -// -// only damage ents that can clearly be seen by the explosion! - - -void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage, falloff; - Vector vecSpot; - - if ( flRadius ) - falloff = flDamage / flRadius; - else - falloff = 1.0; - - int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER); - - vecSrc.z += 1;// in case grenade is lying on the ground - - if ( !pevAttacker ) - pevAttacker = pevInflictor; - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - // blast's don't tavel into or out of water - if (bInWater && pEntity->pev->waterlevel == 0) - continue; - if (!bInWater && pEntity->pev->waterlevel == 3) - continue; - - vecSpot = pEntity->BodyTarget( vecSrc ); - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr ); - - if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - if (tr.fStartSolid) - { - // if we're stuck inside them, fixup the position and distance - tr.vecEndPos = vecSrc; - tr.flFraction = 0.0; - } - - // decrease damage for an ent that's farther from the bomb. - flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff; - flAdjustedDamage = flDamage - flAdjustedDamage; - - if ( flAdjustedDamage < 0 ) - { - flAdjustedDamage = 0; - } - - // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); - ApplyMultiDamage( pevInflictor, pevAttacker ); - } - else - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } -} - - -void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( pev->origin, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - - -void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - ::RadiusDamage( vecSrc, pevInflictor, pevAttacker, flDamage, flDamage * 2.5, iClassIgnore, bitsDamageType ); -} - - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// -// Used for many contact-range melee attacks. Bites, claws, etc. -//========================================================= -CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) -{ - TraceResult tr; - - if (IsPlayer()) - UTIL_MakeVectors( pev->angles ); - else - UTIL_MakeAimVectors( pev->angles ); - - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist ); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( iDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); - } - - return pEntity; - } - - return NULL; -} - - -//========================================================= -// FInViewCone - returns true is the passed ent is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pEntity->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FInViewCone - returns true is the passed vector is in -// the caller's forward view cone. The dot product is performed -// in 2d, making the view cone infinitely tall. -//========================================================= -BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( *pOrigin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - if ( flDot > m_flFieldOfView ) - { - return TRUE; - } - else - { - return FALSE; - } -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target -//========================================================= -BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) -{ - TraceResult tr; - Vector vecLookerOrigin; - Vector vecTargetOrigin; - - if (FBitSet( pEntity->pev->flags, FL_NOTARGET )) - return FALSE; - - // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - return FALSE; - - vecLookerOrigin = pev->origin + pev->view_ofs;//look through the caller's 'eyes' - vecTargetOrigin = pEntity->EyePosition(); - - UTIL_TraceLine(vecLookerOrigin, vecTargetOrigin, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if (tr.flFraction != 1.0) - { - return FALSE;// Line of sight is not established - } - else - { - return TRUE;// line of sight is valid. - } -} - -//========================================================= -// FVisible - returns true if a line can be traced from -// the caller's eyes to the target vector -//========================================================= -BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) -{ - TraceResult tr; - Vector vecLookerOrigin; - - vecLookerOrigin = EyePosition();//look through the caller's 'eyes' - - UTIL_TraceLine(vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if (tr.flFraction != 1.0) - { - return FALSE;// Line of sight is not established - } - else - { - return TRUE;// line of sight is valid. - } -} - -/* -================ -TraceAttack -================ -*/ -void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - } - } -} - - -/* -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - Vector vecOrigin = ptr->vecEndPos - vecDir * 4; - - ALERT ( at_console, "%d\n", ptr->iHitgroup ); - - - if ( pev->takedamage ) - { - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - - int blood = BloodColor(); - - if ( blood != DONT_BLEED ) - { - SpawnBlood(vecOrigin, blood, flDamage);// a little surface blood. - } - } -} -*/ - -//========================================================= -// TraceAttack -//========================================================= -void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.monHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.monChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.monStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.monArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.monLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Monsters. -================ -*/ -void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) -{ - static int tracerCount; - int tracer; - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - ClearMultiDamage(); - gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; - - for (ULONG iShot = 1; iShot <= cShots; iShot++) - { - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - - Vector vecDir = vecDirShooting + - x * vecSpread.x * vecRight + - y * vecSpread.y * vecUp; - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - - tracer = 0; - if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0) - { - Vector vecTracerSrc; - - if ( IsPlayer() ) - {// adjust tracer position for player - vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + gpGlobals->v_right * 2 + gpGlobals->v_forward * 16; - } - else - { - vecTracerSrc = vecSrc; - } - - if ( iTracerFreq != 1 ) // guns that always trace also always decal - tracer = 1; - switch( iBulletType ) - { - case BULLET_MONSTER_MP5: - case BULLET_MONSTER_9MM: - case BULLET_MONSTER_12MM: - default: - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc ); - WRITE_BYTE( TE_TRACER ); - WRITE_COORD( vecTracerSrc.x ); - WRITE_COORD( vecTracerSrc.y ); - WRITE_COORD( vecTracerSrc.z ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - MESSAGE_END(); - break; - } - } - // do damage, paint decals - if (tr.flFraction != 1.0) - { - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if ( iDamage ) - { - pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - else switch(iBulletType) - { - default: - case BULLET_MONSTER_9MM: - pEntity->TraceAttack(pevAttacker, gSkillData.monDmg9MM, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_MP5: - pEntity->TraceAttack(pevAttacker, gSkillData.monDmgMP5, vecDir, &tr, DMG_BULLET); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - - break; - - case BULLET_MONSTER_12MM: - pEntity->TraceAttack(pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); - if ( !tracer ) - { - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - break; - - case BULLET_NONE: // FIX - pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - // only decal glass - if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) - { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); - } - - break; - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, static_cast((flDistance * tr.flFraction) / 64.0) ); - } - ApplyMultiDamage(pev, pevAttacker); -} - - -/* -================ -FireBullets - -Go to the trouble of combining multiple pellets into a single damage call. - -This version is used by Players, uses the random seed generator to sync client and server side shots. -================ -*/ -Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) -{ - TraceResult tr; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - float x = 0.0, y = 0.0; -// float z; - - if ( pevAttacker == NULL ) - pevAttacker = pev; // the default attacker is ourselves - - ClearMultiDamage(); - gMultiDamage.type = DMG_BULLET | DMG_NEVERGIB; - - for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) - { - //Use player's random seed. - // get circular gaussian spread - x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); - y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); -// z = x * x + y * y; - - Vector vecDir = vecDirShooting + - x * vecSpread.x * vecRight + - y * vecSpread.y * vecUp; - Vector vecEnd; - - vecEnd = vecSrc + vecDir * flDistance; - UTIL_TraceLine(vecSrc, vecEnd, dont_ignore_monsters, ENT(pev)/*pentIgnore*/, &tr); - - // do damage, paint decals - if (tr.flFraction != 1.0) - { - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if ( iDamage ) - { - pEntity->TraceAttack(pevAttacker, iDamage, vecDir, &tr, DMG_BULLET | ((iDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB) ); - - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - DecalGunshot( &tr, iBulletType ); - } - else switch(iBulletType) - { - default: - case BULLET_PLAYER_9MM: - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg9MM, vecDir, &tr, DMG_BULLET); - break; - - case BULLET_PLAYER_MP5: - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgMP5, vecDir, &tr, DMG_BULLET); - break; - - case BULLET_PLAYER_BUCKSHOT: - // make distance based! - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmgBuckshot, vecDir, &tr, DMG_BULLET); - break; - - case BULLET_PLAYER_357: - pEntity->TraceAttack(pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET); - break; - - case BULLET_NONE: // FIX - pEntity->TraceAttack(pevAttacker, 50, vecDir, &tr, DMG_CLUB); - TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); - // only decal glass - if ( !FNullEnt(tr.pHit) && VARS(tr.pHit)->rendermode != 0) - { - UTIL_DecalTrace( &tr, DECAL_GLASSBREAK1 + RANDOM_LONG(0,2) ); - } - - break; - } - } - // make bullet trails - UTIL_BubbleTrail( vecSrc, tr.vecEndPos, static_cast((flDistance * tr.flFraction) / 64.0) ); - } - ApplyMultiDamage(pev, pevAttacker); - - return Vector( x * vecSpread.x, y * vecSpread.y, 0.0 ); -} - -void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - if (BloodColor() == DONT_BLEED) - return; - - if (flDamage == 0) - return; - - if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_MORTAR))) - return; - - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - float flNoise; - int cCount; - int i; - -/* - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } -*/ - - if (flDamage < 10) - { - flNoise = 0.1; - cCount = 1; - } - else if (flDamage < 25) - { - flNoise = 0.2; - cCount = 2; - } - else - { - flNoise = 0.3; - cCount = 4; - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * -172, ignore_monsters, ENT(pev), &Bloodtr); - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} - -//========================================================= -//========================================================= -void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) -{ - // make blood decal on the wall! - TraceResult Bloodtr; - Vector vecTraceDir; - int i; - - if ( !IsAlive() ) - { - // dealing with a dead monster. - if ( pev->max_health <= 0 ) - { - // no blood decal for a monster that has already decalled its limit. - return; - } - else - { - pev->max_health--; - } - } - - for ( i = 0 ; i < cCount ; i++ ) - { - vecTraceDir = vecDir; - - vecTraceDir.x += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.y += RANDOM_FLOAT( -flNoise, flNoise ); - vecTraceDir.z += RANDOM_FLOAT( -flNoise, flNoise ); - - UTIL_TraceLine( ptr->vecEndPos, ptr->vecEndPos + vecTraceDir * 172, ignore_monsters, ENT(pev), &Bloodtr); - -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( ptr->vecEndPos.x ); - WRITE_COORD( ptr->vecEndPos.y ); - WRITE_COORD( ptr->vecEndPos.z ); - - WRITE_COORD( Bloodtr.vecEndPos.x ); - WRITE_COORD( Bloodtr.vecEndPos.y ); - WRITE_COORD( Bloodtr.vecEndPos.z ); - MESSAGE_END(); -*/ - - if ( Bloodtr.flFraction != 1.0 ) - { - UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); - } - } -} diff --git a/sdk/dlls/controller.cpp b/sdk/dlls/controller.cpp deleted file mode 100644 index 25f7138..0000000 --- a/sdk/dlls/controller.cpp +++ /dev/null @@ -1,1428 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// CONTROLLER -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "effects.h" -#include "schedule.h" -#include "weapons.h" -#include "squadmonster.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define CONTROLLER_AE_HEAD_OPEN 1 -#define CONTROLLER_AE_BALL_SHOOT 2 -#define CONTROLLER_AE_SMALL_SHOOT 3 -#define CONTROLLER_AE_POWERUP_FULL 4 -#define CONTROLLER_AE_POWERUP_HALF 5 - -#define CONTROLLER_FLINCH_DELAY 2 // at most one flinch every n secs - -class CController : public CSquadMonster -{ -public: - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void RunAI( void ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); // balls - BOOL CheckRangeAttack2 ( float flDot, float flDist ); // head - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // block, throw - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - CUSTOM_SCHEDULES; - - void Stop( void ); - void Move ( float flInterval ); - int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void SetActivity ( Activity NewActivity ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - int LookupFloat( ); - - float m_flNextFlinch; - - float m_flShootTime; - float m_flShootEnd; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - CSprite *m_pBall[2]; // hand balls - int m_iBall[2]; // how bright it should be - float m_iBallTime[2]; // when it should be that color - int m_iBallCurrent[2]; // current brightness - - Vector m_vecEstVelocity; - - Vector m_velocity; - int m_fInCombat; -}; - -LINK_ENTITY_TO_CLASS( monster_alien_controller, CController ); - -TYPEDESCRIPTION CController::m_SaveData[] = -{ - DEFINE_ARRAY( CController, m_pBall, FIELD_CLASSPTR, 2 ), - DEFINE_ARRAY( CController, m_iBall, FIELD_INTEGER, 2 ), - DEFINE_ARRAY( CController, m_iBallTime, FIELD_TIME, 2 ), - DEFINE_ARRAY( CController, m_iBallCurrent, FIELD_INTEGER, 2 ), - DEFINE_FIELD( CController, m_vecEstVelocity, FIELD_VECTOR ), -}; -IMPLEMENT_SAVERESTORE( CController, CSquadMonster ); - - -const char *CController::pAttackSounds[] = -{ - "controller/con_attack1.wav", - "controller/con_attack2.wav", - "controller/con_attack3.wav", -}; - -const char *CController::pIdleSounds[] = -{ - "controller/con_idle1.wav", - "controller/con_idle2.wav", - "controller/con_idle3.wav", - "controller/con_idle4.wav", - "controller/con_idle5.wav", -}; - -const char *CController::pAlertSounds[] = -{ - "controller/con_alert1.wav", - "controller/con_alert2.wav", - "controller/con_alert3.wav", -}; - -const char *CController::pPainSounds[] = -{ - "controller/con_pain1.wav", - "controller/con_pain2.wav", - "controller/con_pain3.wav", -}; - -const char *CController::pDeathSounds[] = -{ - "controller/con_die1.wav", - "controller/con_die2.wav", -}; - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CController :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CController :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CController :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // HACK HACK -- until we fix this. - if ( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CController::Killed( entvars_t *pevAttacker, int iGib ) -{ - // shut off balls - /* - m_iBall[0] = 0; - m_iBallTime[0] = gpGlobals->time + 4.0; - m_iBall[1] = 0; - m_iBallTime[1] = gpGlobals->time + 4.0; - */ - - // fade balls - if (m_pBall[0]) - { - m_pBall[0]->SUB_StartFadeOut(); - m_pBall[0] = NULL; - } - if (m_pBall[1]) - { - m_pBall[1]->SUB_StartFadeOut(); - m_pBall[1] = NULL; - } - - CSquadMonster::Killed( pevAttacker, iGib ); -} - - -void CController::GibMonster( void ) -{ - // delete balls - if (m_pBall[0]) - { - UTIL_Remove( m_pBall[0] ); - m_pBall[0] = NULL; - } - if (m_pBall[1]) - { - UTIL_Remove( m_pBall[1] ); - m_pBall[1] = NULL; - } - CSquadMonster::GibMonster( ); -} - - - - -void CController :: PainSound( void ) -{ - if (RANDOM_LONG(0,5) < 2) - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds ); -} - -void CController :: AlertSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds ); -} - -void CController :: IdleSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pIdleSounds ); -} - -void CController :: AttackSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAttackSounds ); -} - -void CController :: DeathSound( void ) -{ - EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CController :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case CONTROLLER_AE_HEAD_OPEN: - { - Vector vecStart, angleGun; - - GetAttachment( 0, vecStart, angleGun ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( 1 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 20 ); // life * 10 - WRITE_COORD( -32 ); // decay - MESSAGE_END(); - - m_iBall[0] = 192; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - - } - break; - - case CONTROLLER_AE_BALL_SHOOT: - { - Vector vecStart, angleGun; - - GetAttachment( 0, vecStart, angleGun ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( 0 ); // origin - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 32 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 32 ); // decay - MESSAGE_END(); - - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_head_ball", vecStart, pev->angles, edict() ); - - pBall->pev->velocity = Vector( 0, 0, 32 ); - pBall->m_hEnemy = m_hEnemy; - - m_iBall[0] = 0; - m_iBall[1] = 0; - } - break; - - case CONTROLLER_AE_SMALL_SHOOT: - { - AttackSound( ); - m_flShootTime = gpGlobals->time; - m_flShootEnd = m_flShootTime + atoi( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_FULL: - { - m_iBall[0] = 255; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 255; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - case CONTROLLER_AE_POWERUP_HALF: - { - m_iBall[0] = 192; - m_iBallTime[0] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - m_iBall[1] = 192; - m_iBallTime[1] = gpGlobals->time + atoi( pEvent->options ) / 15.0; - } - break; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CController :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/controller.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 )); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - pev->flags |= FL_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.controllerHealth; - pev->view_ofs = Vector( 0, 0, -2 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_FULL;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CController :: Precache() -{ - PRECACHE_MODEL("models/controller.mdl"); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - - PRECACHE_MODEL( "sprites/xspark4.spr"); - - UTIL_PrecacheOther( "controller_energy_ball" ); - UTIL_PrecacheOther( "controller_head_ball" ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - -// Chase enemy schedule -Task_t tlControllerChaseEnemy[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - -}; - -Schedule_t slControllerChaseEnemy[] = -{ - { - tlControllerChaseEnemy, - ARRAYSIZE ( tlControllerChaseEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_TASK_FAILED, - 0, - "ControllerChaseEnemy" - }, -}; - - - -Task_t tlControllerStrafe[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_GET_PATH_TO_ENEMY, (float)128 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerStrafe[] = -{ - { - tlControllerStrafe, - ARRAYSIZE ( tlControllerStrafe ), - bits_COND_NEW_ENEMY, - 0, - "ControllerStrafe" - }, -}; - - -Task_t tlControllerTakeCover[] = -{ - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slControllerTakeCover[] = -{ - { - tlControllerTakeCover, - ARRAYSIZE ( tlControllerTakeCover ), - bits_COND_NEW_ENEMY, - 0, - "ControllerTakeCover" - }, -}; - - -Task_t tlControllerFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slControllerFail[] = -{ - { - tlControllerFail, - ARRAYSIZE ( tlControllerFail ), - 0, - 0, - "ControllerFail" - }, -}; - - - -DEFINE_CUSTOM_SCHEDULES( CController ) -{ - slControllerChaseEnemy, - slControllerStrafe, - slControllerTakeCover, - slControllerFail, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CController, CSquadMonster ); - - - -//========================================================= -// StartTask -//========================================================= -void CController :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - CSquadMonster :: StartTask ( pTask ); - break; - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, pTask->flData, (m_vecEnemyLKP - pev->origin).Length() + 1024 )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, pTask->flData, (pEnemy->pev->origin - pev->origin).Length() + 1024 )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - default: - CSquadMonster :: StartTask ( pTask ); - break; - } -} - - -Vector Intersect( Vector vecSrc, Vector vecDst, Vector vecMove, float flSpeed ) -{ - Vector vecTo = vecDst - vecSrc; - - float a = DotProduct( vecMove, vecMove ) - flSpeed * flSpeed; - float b = 0 * DotProduct(vecTo, vecMove); // why does this work? - float c = DotProduct( vecTo, vecTo ); - - float t; - if (a == 0) - { - t = c / (flSpeed * flSpeed); - } - else - { - t = b * b - 4 * a * c; - t = sqrt( t ) / (2.0 * a); - float t1 = -b +t; - float t2 = -b -t; - - if (t1 < 0 || t2 < t1) - t = t2; - else - t = t1; - } - - // ALERT( at_console, "Intersect %f\n", t ); - - if (t < 0.1) - t = 0.1; - if (t > 10.0) - t = 10.0; - - Vector vecHit = vecTo + vecMove * t; - return vecHit.Normalize( ) * flSpeed; -} - - -int CController::LookupFloat( ) -{ - if (m_velocity.Length( ) < 32.0) - { - return LookupSequence( "up" ); - } - - UTIL_MakeAimVectors( pev->angles ); - float x = DotProduct( gpGlobals->v_forward, m_velocity ); - float y = DotProduct( gpGlobals->v_right, m_velocity ); - float z = DotProduct( gpGlobals->v_up, m_velocity ); - - if (fabs(x) > fabs(y) && fabs(x) > fabs(z)) - { - if (x > 0) - return LookupSequence( "forward"); - else - return LookupSequence( "backward"); - } - else if (fabs(y) > fabs(z)) - { - if (y > 0) - return LookupSequence( "right"); - else - return LookupSequence( "left"); - } - else - { - if (z > 0) - return LookupSequence( "up"); - else - return LookupSequence( "down"); - } -} - - -//========================================================= -// RunTask -//========================================================= -void CController :: RunTask ( Task_t *pTask ) -{ - - if (m_flShootEnd > gpGlobals->time) - { - Vector vecHand, vecAngle; - - GetAttachment( 2, vecHand, vecAngle ); - - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) - { - Vector vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - Vector vecDir; - - if (m_hEnemy != 0) - { - if (HasConditions( bits_COND_SEE_ENEMY )) - { - m_vecEstVelocity = m_vecEstVelocity * 0.5 + m_hEnemy->pev->velocity * 0.5; - } - else - { - m_vecEstVelocity = m_vecEstVelocity * 0.8; - } - vecDir = Intersect( vecSrc, m_hEnemy->BodyTarget( pev->origin ), m_vecEstVelocity, gSkillData.controllerSpeedBall ); - float delta = 0.03490; // +-2 degree - vecDir = vecDir + Vector( RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ), RANDOM_FLOAT( -delta, delta ) ) * gSkillData.controllerSpeedBall; - - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - CBaseMonster *pBall = (CBaseMonster*)Create( "controller_energy_ball", vecSrc, pev->angles, edict() ); - pBall->pev->velocity = vecDir; - } - m_flShootTime += 0.2; - } - - if (m_flShootTime > m_flShootEnd) - { - m_iBall[0] = 64; - m_iBallTime[0] = m_flShootEnd; - m_iBall[1] = 64; - m_iBallTime[1] = m_flShootEnd; - m_fInCombat = FALSE; - } - } - - switch ( pTask->iTask ) - { - case TASK_WAIT_FOR_MOVEMENT: - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - case TASK_WAIT_PVS: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if (m_fSequenceFinished) - { - m_fInCombat = FALSE; - } - - CSquadMonster :: RunTask ( pTask ); - - if (!m_fInCombat) - { - if (HasConditions ( bits_COND_CAN_RANGE_ATTACK1 )) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK1 ); - pev->frame = 0; - ResetSequenceInfo( ); - m_fInCombat = TRUE; - } - else if (HasConditions ( bits_COND_CAN_RANGE_ATTACK2 )) - { - pev->sequence = LookupActivity( ACT_RANGE_ATTACK2 ); - pev->frame = 0; - ResetSequenceInfo( ); - m_fInCombat = TRUE; - } - else - { - int iFloat = LookupFloat( ); - if (m_fSequenceFinished || iFloat != pev->sequence) - { - pev->sequence = iFloat; - pev->frame = 0; - ResetSequenceInfo( ); - } - } - } - break; - default: - CSquadMonster :: RunTask ( pTask ); - break; - } -} - - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CController :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - break; - - case MONSTERSTATE_ALERT: - break; - - case MONSTERSTATE_COMBAT: - { - Intersect( Vector( 0, 0, 0 ), Vector( 100, 4, 7 ), Vector( 2, 10, -3 ), 20.0 ); - - // dead enemy - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) - { - // m_iFrustration++; - } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - // m_iFrustration++; - } - } - break; - default: - break; - } - - return CSquadMonster :: GetSchedule(); -} - - - -//========================================================= -//========================================================= -Schedule_t* CController :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) - { - case SCHED_CHASE_ENEMY: - return slControllerChaseEnemy; - case SCHED_RANGE_ATTACK1: - return slControllerStrafe; - case SCHED_RANGE_ATTACK2: - case SCHED_MELEE_ATTACK1: - case SCHED_MELEE_ATTACK2: - case SCHED_TAKE_COVER_FROM_ENEMY: - return slControllerTakeCover; - case SCHED_FAIL: - return slControllerFail; - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - - - - - -//========================================================= -// CheckRangeAttack1 - shoot a bigass energy ball out of their head -// -//========================================================= -BOOL CController :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDot > 0.5 && flDist > 256 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - - -BOOL CController :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if ( flDot > 0.5 && flDist > 64 && flDist <= 2048 ) - { - return TRUE; - } - return FALSE; -} - - -BOOL CController :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - return FALSE; -} - - -void CController :: SetActivity ( Activity NewActivity ) -{ - CBaseMonster::SetActivity( NewActivity ); - - switch ( m_Activity) - { - case ACT_WALK: - m_flGroundSpeed = 100; - break; - default: - m_flGroundSpeed = 100; - break; - } -} - - - -//========================================================= -// RunAI -//========================================================= -void CController :: RunAI( void ) -{ - CBaseMonster :: RunAI(); - Vector vecStart, angleGun; - - if ( HasMemory( bits_MEMORY_KILLED ) ) - return; - - for (int i = 0; i < 2; i++) - { - if (m_pBall[i] == NULL) - { - m_pBall[i] = CSprite::SpriteCreate( "sprites/xspark4.spr", pev->origin, TRUE ); - m_pBall[i]->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall[i]->SetAttachment( edict(), (i + 3) ); - m_pBall[i]->SetScale( 1.0 ); - } - - float t = m_iBallTime[i] - gpGlobals->time; - if (t > 0.1) - t = 0.1 / t; - else - t = 1.0; - - m_iBallCurrent[i] += (m_iBall[i] - m_iBallCurrent[i]) * t; - - m_pBall[i]->SetBrightness( m_iBallCurrent[i] ); - - GetAttachment( i + 2, vecStart, angleGun ); - UTIL_SetOrigin( m_pBall[i]->pev, vecStart ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 * (i + 3) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( m_iBallCurrent[i] / 8 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 5 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } -} - - -extern void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ); - -void CController::Stop( void ) -{ - m_IdealActivity = GetStoppedActivity(); -} - - -#define DIST_TO_CHECK 200 -void CController :: Move ( float flInterval ) -{ - float flWaypointDist; - float flCheckDist; - float flDist;// how far the lookahead check got before hitting an object. - float flMoveDist; - Vector vecDir; - Vector vecApex; - CBaseEntity *pTargetEnt; - - // Don't move if no valid route - if ( FRouteClear() ) - { - ALERT( at_aiconsole, "Tried to move with no route!\n" ); - TaskFail(); - return; - } - - if ( m_flMoveWaitFinished > gpGlobals->time ) - return; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - return; - } -#else -// Debug, draw the route -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); -#endif - - // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer - // to that entity for the CheckLocalMove and Triangulate functions. - pTargetEnt = NULL; - - if (m_flGroundSpeed == 0) - { - m_flGroundSpeed = 100; - // TaskFail( ); - // return; - } - - flMoveDist = m_flGroundSpeed * flInterval; - - do - { - // local move to waypoint. - vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); - - // MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - // ChangeYaw ( pev->yaw_speed ); - - // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint - if ( flWaypointDist < DIST_TO_CHECK ) - { - flCheckDist = flWaypointDist; - } - else - { - flCheckDist = DIST_TO_CHECK; - } - - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) - { - // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) - pTargetEnt = m_hEnemy; - } - else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) - { - pTargetEnt = m_hTargetEnt; - } - - // !!!BUGBUG - CheckDist should be derived from ground speed. - // If this fails, it should be because of some dynamic entity blocking this guy. - // We've already checked this path, so we should wait and time out if the entity doesn't move - flDist = 0; - if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) - { - CBaseEntity *pBlocker; - - // Can't move, stop - Stop(); - // Blocking entity is in global trace_ent - pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) - { - DispatchBlocked( edict(), pBlocker->edict() ); - } - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) - { - // Can we still move toward our target? - if ( flDist < m_flGroundSpeed ) - { - // Wait for a second - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - // ALERT( at_aiconsole, "Move %s!!!\n", STRING( pBlocker->pev->classname ) ); - return; - } - } - else - { - // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); - RouteSimplify( pTargetEnt ); - } - else - { - ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); - Stop(); - if ( m_moveWaitTime > 0 ) - { - FRefreshRoute(); - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime * 0.5; - } - else - { - TaskFail(); - ALERT( at_aiconsole, "Failed to move!\n" ); - //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); - } - return; - } - } - } - - // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if (flCheckDist < flMoveDist) - { - MoveExecute( pTargetEnt, vecDir, flCheckDist / m_flGroundSpeed ); - - // ALERT( at_console, "%.02f\n", flInterval ); - AdvanceRoute( flWaypointDist ); - flMoveDist -= flCheckDist; - } - else - { - MoveExecute( pTargetEnt, vecDir, flMoveDist / m_flGroundSpeed ); - - if ( ShouldAdvanceRoute( flWaypointDist - flMoveDist ) ) - { - AdvanceRoute( flWaypointDist ); - } - flMoveDist = 0; - } - - if ( MovementIsComplete() ) - { - Stop(); - RouteClear(); - } - } while (flMoveDist > 0 && flCheckDist > 0); - - // cut corner? - if (flWaypointDist < 128) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - - if (m_flGroundSpeed > 100) - m_flGroundSpeed -= 40; - } - else - { - if (m_flGroundSpeed < 400) - m_flGroundSpeed += 10; - } -} - - - -BOOL CController:: ShouldAdvanceRoute( float flWaypointDist ) -{ - if ( flWaypointDist <= 32 ) - { - return TRUE; - } - - return FALSE; -} - - -int CController :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32), vecEnd + Vector( 0, 0, 32), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if (pflDist) - { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - - -void CController::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if ( m_IdealActivity != m_movementActivity ) - m_IdealActivity = m_movementActivity; - - // ALERT( at_console, "move %.4f %.4f %.4f : %f\n", vecDir.x, vecDir.y, vecDir.z, flInterval ); - - // float flTotal = m_flGroundSpeed * pev->framerate * flInterval; - // UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flTotal, MOVE_STRAFE ); - - m_velocity = m_velocity * 0.8 + m_flGroundSpeed * vecDir * 0.2; - - UTIL_MoveToOrigin ( ENT(pev), pev->origin + m_velocity, m_velocity.Length() * flInterval, MOVE_STRAFE ); - -} - - - - -//========================================================= -// Controller bouncy ball attack -//========================================================= -class CControllerHeadBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT HuntThink( void ); - void EXPORT DieThink( void ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void MovetoTarget( Vector vecTarget ); - void Crawl( void ); - int m_flNextAttack; - Vector m_vecIdeal; - EHANDLE m_hOwner; -}; -LINK_ENTITY_TO_CLASS( controller_head_ball, CControllerHeadBall ); - - - -void CControllerHeadBall :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 2.0; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerHeadBall::HuntThink ); - SetTouch( &CControllerHeadBall::BounceTouch ); - - m_vecIdeal = Vector( 0, 0, 0 ); - - pev->nextthink = gpGlobals->time + 0.1; - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; -} - - -void CControllerHeadBall :: Precache( void ) -{ - PRECACHE_MODEL("sprites/xspark1.spr"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); -} - - -void CControllerHeadBall :: HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->renderamt -= 5; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt / 16 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - - // check world boundaries - if (gpGlobals->time - pev->dmgtime > 5 || pev->renderamt < 64 || m_hEnemy == 0 || m_hOwner == 0 || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - MovetoTarget( m_hEnemy->Center( ) ); - - if ((m_hEnemy->Center() - pev->origin).Length() < 64) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, ENT(pev), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - ClearMultiDamage( ); - pEntity->TraceAttack( m_hOwner->pev, gSkillData.controllerDmgZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, m_hOwner->pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - m_flNextAttack = gpGlobals->time + 3.0; - - SetThink( &CControllerHeadBall::DieThink ); - pev->nextthink = gpGlobals->time + 0.3; - } - - // Crawl( ); -} - - -void CControllerHeadBall :: DieThink( void ) -{ - UTIL_Remove( this ); -} - - -void CControllerHeadBall :: MovetoTarget( Vector vecTarget ) -{ - // accelerate - float flSpeed = m_vecIdeal.Length(); - if (flSpeed == 0) - { - m_vecIdeal = pev->velocity; - flSpeed = m_vecIdeal.Length(); - } - - if (flSpeed > 400) - { - m_vecIdeal = m_vecIdeal.Normalize( ) * 400; - } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 100; - pev->velocity = m_vecIdeal; -} - - - -void CControllerHeadBall :: Crawl( void ) -{ - - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); - Vector vecPnt = pev->origin + pev->velocity * 0.3 + vecAim * 64; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x); - WRITE_COORD( vecPnt.y); - WRITE_COORD( vecPnt.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - - -void CControllerHeadBall::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize( ); - - TraceResult tr = UTIL_GetGlobalTrace( ); - - float n = -DotProduct(tr.vecPlaneNormal, vecDir); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} - - - - -class CControllerZapBall : public CBaseMonster -{ - void Spawn( void ); - void Precache( void ); - void EXPORT AnimateThink( void ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - - EHANDLE m_hOwner; -}; -LINK_ENTITY_TO_CLASS( controller_energy_ball, CControllerZapBall ); - - -void CControllerZapBall :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "sprites/xspark4.spr"); - pev->rendermode = kRenderTransAdd; - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->renderamt = 255; - pev->scale = 0.5; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CControllerZapBall::AnimateThink ); - SetTouch( &CControllerZapBall::ExplodeTouch ); - - m_hOwner = Instance( pev->owner ); - pev->dmgtime = gpGlobals->time; // keep track of when ball spawned - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CControllerZapBall :: Precache( void ) -{ - PRECACHE_MODEL("sprites/xspark4.spr"); - // PRECACHE_SOUND("debris/zap4.wav"); - // PRECACHE_SOUND("weapons/electro4.wav"); -} - - -void CControllerZapBall :: AnimateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - pev->frame = ((int)pev->frame + 1) % 11; - - if (gpGlobals->time - pev->dmgtime > 5 || pev->velocity.Length() < 10) - { - SetTouch( NULL ); - UTIL_Remove( this ); - } -} - - -void CControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) -{ - if (pOther->pev->takedamage) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - - entvars_t *pevOwner; - if (m_hOwner != 0) - { - pevOwner = m_hOwner->pev; - } - else - { - pevOwner = pev; - } - - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, gSkillData.controllerDmgBall, pev->velocity.Normalize(), &tr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pevOwner, pevOwner ); - - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.3, ATTN_NORM, 0, RANDOM_LONG( 90, 99 ) ); - - } - - UTIL_Remove( this ); -} - - - -#endif // !OEM && !HLDEMO diff --git a/sdk/dlls/crossbow.cpp b/sdk/dlls/crossbow.cpp deleted file mode 100644 index 6a3779a..0000000 --- a/sdk/dlls/crossbow.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -#ifndef CLIENT_DLL -#define BOLT_AIR_VELOCITY 2000 -#define BOLT_WATER_VELOCITY 1000 - -// UNDONE: Save/restore this? Don't forget to set classname and LINK_ENTITY_TO_CLASS() -// -// OVERLOADS SOME ENTVARS: -// -// speed - the ideal magnitude of my velocity -class CCrossbowBolt : public CBaseEntity -{ - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - void EXPORT BubbleThink( void ); - void EXPORT BoltTouch( CBaseEntity *pOther ); - void EXPORT ExplodeThink( void ); - - int m_iTrail; - -public: - static CCrossbowBolt *BoltCreate( void ); -}; -LINK_ENTITY_TO_CLASS( crossbow_bolt, CCrossbowBolt ); - -CCrossbowBolt *CCrossbowBolt::BoltCreate( void ) -{ - // Create a new entity with CCrossbowBolt private data - CCrossbowBolt *pBolt = GetClassPtr( (CCrossbowBolt *)NULL ); - pBolt->pev->classname = MAKE_STRING("bolt"); - pBolt->Spawn(); - - return pBolt; -} - -void CCrossbowBolt::Spawn( ) -{ - Precache( ); - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->gravity = 0.5; - - SET_MODEL(ENT(pev), "models/crossbow_bolt.mdl"); - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - - SetTouch( &CCrossbowBolt::BoltTouch ); - SetThink( &CCrossbowBolt::BubbleThink ); - pev->nextthink = gpGlobals->time + 0.2; -} - - -void CCrossbowBolt::Precache( ) -{ - PRECACHE_MODEL ("models/crossbow_bolt.mdl"); - PRECACHE_SOUND("weapons/xbow_hitbod1.wav"); - PRECACHE_SOUND("weapons/xbow_hitbod2.wav"); - PRECACHE_SOUND("weapons/xbow_fly1.wav"); - PRECACHE_SOUND("weapons/xbow_hit1.wav"); - PRECACHE_SOUND("fvox/beep.wav"); - m_iTrail = PRECACHE_MODEL("sprites/streak.spr"); -} - - -int CCrossbowBolt :: Classify ( void ) -{ - return CLASS_NONE; -} - -void CCrossbowBolt::BoltTouch( CBaseEntity *pOther ) -{ - SetTouch( NULL ); - SetThink( NULL ); - - if (pOther->pev->takedamage) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - entvars_t *pevOwner; - - pevOwner = VARS( pev->owner ); - - // UNDONE: this needs to call TraceAttack instead - ClearMultiDamage( ); - - if ( pOther->IsPlayer() ) - { - pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowClient, pev->velocity.Normalize(), &tr, DMG_NEVERGIB ); - } - else - { - pOther->TraceAttack(pevOwner, gSkillData.plrDmgCrossbowMonster, pev->velocity.Normalize(), &tr, DMG_BULLET | DMG_NEVERGIB ); - } - - ApplyMultiDamage( pev, pevOwner ); - - pev->velocity = Vector( 0, 0, 0 ); - // play body "thwack" sound - switch( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM); break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM); break; - } - - if ( !g_pGameRules->IsMultiplayer() ) - { - Killed( pev, GIB_NEVER ); - } - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "weapons/xbow_hit1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,7)); - - SetThink( &CCrossbowBolt::SUB_Remove ); - pev->nextthink = gpGlobals->time;// this will get changed below if the bolt is allowed to stick in what it hit. - - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) - { - // if what we hit is static architecture, can stay around for a while. - Vector vecDir = pev->velocity.Normalize( ); - UTIL_SetOrigin( pev, pev->origin - vecDir * 12 ); - pev->angles = UTIL_VecToAngles( vecDir ); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_FLY; - pev->velocity = Vector( 0, 0, 0 ); - pev->avelocity.z = 0; - pev->angles.z = RANDOM_LONG(0,360); - pev->nextthink = gpGlobals->time + 10.0; - } - - if (UTIL_PointContents(pev->origin) != CONTENTS_WATER) - { - UTIL_Sparks( pev->origin ); - } - } - - if ( g_pGameRules->IsMultiplayer() ) - { - SetThink( &CCrossbowBolt::ExplodeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - -void CCrossbowBolt::BubbleThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->waterlevel == 0) - return; - - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 1 ); -} - -void CCrossbowBolt::ExplodeThink( void ) -{ - int iContents = UTIL_PointContents ( pev->origin ); - int iScale; - - pev->dmg = 40; - iScale = 10; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( iScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - entvars_t *pevOwner; - - if ( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - - pev->owner = NULL; // can't traceline attack owner if this is set - - ::RadiusDamage( pev->origin, pev, pevOwner, pev->dmg, 128, CLASS_NONE, DMG_BLAST | DMG_ALWAYSGIB ); - - UTIL_Remove(this); -} -#endif - -enum crossbow_e { - CROSSBOW_IDLE1 = 0, // full - CROSSBOW_IDLE2, // empty - CROSSBOW_FIDGET1, // full - CROSSBOW_FIDGET2, // empty - CROSSBOW_FIRE1, // full - CROSSBOW_FIRE2, // reload - CROSSBOW_FIRE3, // empty - CROSSBOW_RELOAD, // from empty - CROSSBOW_DRAW1, // full - CROSSBOW_DRAW2, // empty - CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty -}; - -LINK_ENTITY_TO_CLASS( weapon_crossbow, CCrossbow ); - -void CCrossbow::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_CROSSBOW; - SET_MODEL(ENT(pev), "models/w_crossbow.mdl"); - - m_iDefaultAmmo = CROSSBOW_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - -int CCrossbow::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CCrossbow::Precache( void ) -{ - PRECACHE_MODEL("models/w_crossbow.mdl"); - PRECACHE_MODEL("models/v_crossbow.mdl"); - PRECACHE_MODEL("models/p_crossbow.mdl"); - - PRECACHE_SOUND("weapons/xbow_fire1.wav"); - PRECACHE_SOUND("weapons/xbow_reload1.wav"); - - UTIL_PrecacheOther( "crossbow_bolt" ); - - m_usCrossbow = PRECACHE_EVENT( 1, "events/crossbow1.sc" ); - m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" ); -} - - -int CCrossbow::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "bolts"; - p->iMaxAmmo1 = BOLT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = CROSSBOW_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 2; - p->iId = WEAPON_CROSSBOW; - p->iFlags = 0; - p->iWeight = CROSSBOW_WEIGHT; - return 1; -} - - -BOOL CCrossbow::Deploy( ) -{ - if (m_iClip) - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW1, "bow" ); - return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); -} - -void CCrossbow::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if ( m_fInZoom ) - { - SecondaryAttack( ); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - if (m_iClip) - SendWeaponAnim( CROSSBOW_HOLSTER1 ); - else - SendWeaponAnim( CROSSBOW_HOLSTER2 ); -} - -void CCrossbow::PrimaryAttack( void ) -{ - -#ifdef CLIENT_DLL - if ( m_fInZoom && bIsMultiplayer() ) -#else - if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) -#endif - { - FireSniperBolt(); - return; - } - - FireBolt(); -} - -// this function only gets called in multiplayer -void CCrossbow::FireSniperBolt() -{ - m_flNextPrimaryAttack = GetNextAttackDelay(0.75); - - if (m_iClip == 0) - { - PlayEmptySound( ); - return; - } - - TraceResult tr; - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - - UTIL_TraceLine(vecSrc, vecSrc + vecDir * 8192, dont_ignore_monsters, m_pPlayer->edict(), &tr); - -#ifndef CLIENT_DLL - if ( tr.pHit->v.takedamage ) - { - ClearMultiDamage( ); - CBaseEntity::Instance(tr.pHit)->TraceAttack(m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB ); - ApplyMultiDamage( pev, m_pPlayer->pev ); - } -#endif -} - -void CCrossbow::FireBolt() -{ - TraceResult tr; - - if (m_iClip == 0) - { - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector anglesAim = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - UTIL_MakeVectors( anglesAim ); - - anglesAim.x = -anglesAim.x; -#ifndef CLIENT_DLL - Vector vecSrc = m_pPlayer->GetGunPosition( ) - gpGlobals->v_up * 2; - Vector vecDir = gpGlobals->v_forward; - CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate(); - pBolt->pev->origin = vecSrc; - pBolt->pev->angles = anglesAim; - pBolt->pev->owner = m_pPlayer->edict(); - - if (m_pPlayer->pev->waterlevel == 3) - { - pBolt->pev->velocity = vecDir * BOLT_WATER_VELOCITY; - pBolt->pev->speed = BOLT_WATER_VELOCITY; - } - else - { - pBolt->pev->velocity = vecDir * BOLT_AIR_VELOCITY; - pBolt->pev->speed = BOLT_AIR_VELOCITY; - } - pBolt->pev->avelocity.z = 10; -#endif - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = GetNextAttackDelay(0.75); - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; -} - - -void CCrossbow::SecondaryAttack() -{ - if ( m_pPlayer->pev->fov != 0 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - m_fInZoom = 0; - } - else if ( m_pPlayer->pev->fov != 20 ) - { - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 20; - m_fInZoom = 1; - } - - pev->nextthink = UTIL_WeaponTimeBase() + 0.1; - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; -} - - -void CCrossbow::Reload( void ) -{ - if ( m_pPlayer->ammo_bolts <= 0 ) - return; - - if ( m_pPlayer->pev->fov != 0 ) - { - SecondaryAttack(); - } - - if ( DefaultReload( 5, CROSSBOW_RELOAD, 4.5 ) ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT(0.95, 1.0), ATTN_NORM, 0, 93 + RANDOM_LONG(0,0xF)); - } -} - - -void CCrossbow::WeaponIdle( void ) -{ - m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM - - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - if (m_iClip) - { - SendWeaponAnim( CROSSBOW_IDLE1 ); - } - else - { - SendWeaponAnim( CROSSBOW_IDLE2 ); - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - if (m_iClip) - { - SendWeaponAnim( CROSSBOW_FIDGET1 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; - } - else - { - SendWeaponAnim( CROSSBOW_FIDGET2 ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; - } - } - } -} - - - -class CCrossbowAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_crossbow_clip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_crossbow_clip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_CROSSBOWCLIP_GIVE, "bolts", BOLT_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_crossbow, CCrossbowAmmo ); - - - -#endif diff --git a/sdk/dlls/crowbar.cpp b/sdk/dlls/crowbar.cpp deleted file mode 100644 index ef4a333..0000000 --- a/sdk/dlls/crowbar.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - - -#define CROWBAR_BODYHIT_VOLUME 128 -#define CROWBAR_WALLHIT_VOLUME 512 - -LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ); - - - -enum gauss_e { - CROWBAR_IDLE = 0, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT -}; - - -void CCrowbar::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_CROWBAR; - SET_MODEL(ENT(pev), "models/w_crowbar.mdl"); - m_iClip = -1; - - FallInit();// get ready to fall down. -} - - -void CCrowbar::Precache( void ) -{ - PRECACHE_MODEL("models/v_crowbar.mdl"); - PRECACHE_MODEL("models/w_crowbar.mdl"); - PRECACHE_MODEL("models/p_crowbar.mdl"); - PRECACHE_SOUND("weapons/cbar_hit1.wav"); - PRECACHE_SOUND("weapons/cbar_hit2.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod1.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod2.wav"); - PRECACHE_SOUND("weapons/cbar_hitbod3.wav"); - PRECACHE_SOUND("weapons/cbar_miss1.wav"); - - m_usCrowbar = PRECACHE_EVENT ( 1, "events/crowbar.sc" ); -} - -int CCrowbar::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = NULL; - p->iMaxAmmo1 = -1; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 0; - p->iPosition = 0; - p->iId = WEAPON_CROWBAR; - p->iWeight = CROWBAR_WEIGHT; - return 1; -} - - - -BOOL CCrowbar::Deploy( ) -{ - return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); -} - -void CCrowbar::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( CROWBAR_HOLSTER ); -} - - -void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity ) -{ - int i, j, k; - float distance; - float *minmaxs[2] = {mins, maxs}; - TraceResult tmpTrace; - Vector vecHullEnd = tr.vecEndPos; - Vector vecEnd; - - distance = 1e6f; - - vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); - UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - tr = tmpTrace; - return; - } - - for ( i = 0; i < 2; i++ ) - { - for ( j = 0; j < 2; j++ ) - { - for ( k = 0; k < 2; k++ ) - { - vecEnd.x = vecHullEnd.x + minmaxs[i][0]; - vecEnd.y = vecHullEnd.y + minmaxs[j][1]; - vecEnd.z = vecHullEnd.z + minmaxs[k][2]; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace ); - if ( tmpTrace.flFraction < 1.0 ) - { - float thisDistance = (tmpTrace.vecEndPos - vecSrc).Length(); - if ( thisDistance < distance ) - { - tr = tmpTrace; - distance = thisDistance; - } - } - } - } - } -} - - -void CCrowbar::PrimaryAttack() -{ - if (! Swing( 1 )) - { - SetThink( &CCrowbar::SwingAgain ); - pev->nextthink = gpGlobals->time + 0.1; - } -} - - -void CCrowbar::Smack( ) -{ - DecalGunshot( &m_trHit, BULLET_PLAYER_CROWBAR ); -} - - -void CCrowbar::SwingAgain( void ) -{ - Swing( 0 ); -} - - -int CCrowbar::Swing( int fFirst ) -{ - int fDidHit = FALSE; - - TraceResult tr; - - UTIL_MakeVectors (m_pPlayer->pev->v_angle); - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecEnd = vecSrc + gpGlobals->v_forward * 32; - - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); - -#ifndef CLIENT_DLL - if ( tr.flFraction >= 1.0 ) - { - UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr ); - if ( tr.flFraction < 1.0 ) - { - // Calculate the point of intersection of the line (or hull) and the object we hit - // This is and approximation of the "best" intersection - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - if ( !pHit || pHit->IsBSPModel() ) - FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() ); - vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space) - } - } -#endif - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar, - 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, - 0, 0, 0 ); - - - if ( tr.flFraction >= 1.0 ) - { - if (fFirst) - { - // miss - m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - } - else - { - switch( ((m_iSwing++) % 2) + 1 ) - { - case 0: - SendWeaponAnim( CROWBAR_ATTACK1HIT ); break; - case 1: - SendWeaponAnim( CROWBAR_ATTACK2HIT ); break; - case 2: - SendWeaponAnim( CROWBAR_ATTACK3HIT ); break; - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#ifndef CLIENT_DLL - - // hit - fDidHit = TRUE; - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - ClearMultiDamage( ); - - if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) - { - // first swing does full damage - pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); - } - else - { - // subsequent swings do half - pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB ); - } - ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); - - // play thwack, smack, or dong sound - float flVol = 1.0; - int fHitWorld = TRUE; - - if (pEntity) - { - if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE ) - { - // play thwack or smack sound - switch( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); break; - case 2: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); break; - } - m_pPlayer->m_iWeaponVolume = CROWBAR_BODYHIT_VOLUME; - if ( !pEntity->IsAlive() ) - return TRUE; - else - flVol = 0.1; - - fHitWorld = FALSE; - } - } - - // play texture hit sound - // UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line - - if (fHitWorld) - { - float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_CROWBAR); - - if ( g_pGameRules->IsMultiplayer() ) - { - // override the volume here, cause we don't play texture sounds in multiplayer, - // and fvolbar is going to be 0 from the above call. - - fvolbar = 1; - } - - // also play crowbar strike - switch( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); - break; - case 1: - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/cbar_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); - break; - } - - // delay the decal a bit - m_trHit = tr; - } - - m_pPlayer->m_iWeaponVolume = static_cast(flVol * CROWBAR_WALLHIT_VOLUME); -#endif - m_flNextPrimaryAttack = GetNextAttackDelay(0.25); - - SetThink( &CCrowbar::Smack ); - pev->nextthink = UTIL_WeaponTimeBase() + 0.2; - - - } - return fDidHit; -} - - - diff --git a/sdk/dlls/decals.h b/sdk/dlls/decals.h deleted file mode 100644 index 4fe9c52..0000000 --- a/sdk/dlls/decals.h +++ /dev/null @@ -1,75 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef DECALS_H -#define DECALS_H - -// -// Dynamic Decals -// -enum decal_e -{ - DECAL_GUNSHOT1 = 0, - DECAL_GUNSHOT2, - DECAL_GUNSHOT3, - DECAL_GUNSHOT4, - DECAL_GUNSHOT5, - DECAL_LAMBDA1, - DECAL_LAMBDA2, - DECAL_LAMBDA3, - DECAL_LAMBDA4, - DECAL_LAMBDA5, - DECAL_LAMBDA6, - DECAL_SCORCH1, - DECAL_SCORCH2, - DECAL_BLOOD1, - DECAL_BLOOD2, - DECAL_BLOOD3, - DECAL_BLOOD4, - DECAL_BLOOD5, - DECAL_BLOOD6, - DECAL_YBLOOD1, - DECAL_YBLOOD2, - DECAL_YBLOOD3, - DECAL_YBLOOD4, - DECAL_YBLOOD5, - DECAL_YBLOOD6, - DECAL_GLASSBREAK1, - DECAL_GLASSBREAK2, - DECAL_GLASSBREAK3, - DECAL_BIGSHOT1, - DECAL_BIGSHOT2, - DECAL_BIGSHOT3, - DECAL_BIGSHOT4, - DECAL_BIGSHOT5, - DECAL_SPIT1, - DECAL_SPIT2, - DECAL_BPROOF1, // Bulletproof glass decal - DECAL_GARGSTOMP1, // Gargantua stomp crack - DECAL_SMALLSCORCH1, // Small scorch mark - DECAL_SMALLSCORCH2, // Small scorch mark - DECAL_SMALLSCORCH3, // Small scorch mark - DECAL_MOMMABIRTH, // Big momma birth splatter - DECAL_MOMMASPLAT, -}; - -typedef struct -{ - const char *name; - int index; -} DLL_DECALLIST; - -extern DLL_DECALLIST gDecals[]; - -#endif // DECALS_H diff --git a/sdk/dlls/defaultai.cpp b/sdk/dlls/defaultai.cpp deleted file mode 100644 index 6f231ad..0000000 --- a/sdk/dlls/defaultai.cpp +++ /dev/null @@ -1,1232 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Default behaviors. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "defaultai.h" -#include "soundent.h" -#include "nodes.h" -#include "scripted.h" - -//========================================================= -// Fail -//========================================================= -Task_t tlFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slFail[] = -{ - { - tlFail, - ARRAYSIZE ( tlFail ), - bits_COND_CAN_ATTACK, - 0, - "Fail" - }, -}; - -//========================================================= -// Idle Schedules -//========================================================= -Task_t tlIdleStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)5 },// repick IDLESTAND every five seconds. gives us a chance to pick an active idle, fidget, etc. -}; - -Schedule_t slIdleStand[] = -{ - { - tlIdleStand1, - ARRAYSIZE ( tlIdleStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL_FOOD | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER | - - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleStand" - }, -}; - -Schedule_t slIdleTrigger[] = -{ - { - tlIdleStand1, - ARRAYSIZE ( tlIdleStand1 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Trigger" - }, -}; - - -Task_t tlIdleWalk1[] = -{ - { TASK_WALK_PATH, (float)9999 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slIdleWalk[] = -{ - { - tlIdleWalk1, - ARRAYSIZE ( tlIdleWalk1 ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL_FOOD | - bits_COND_SMELL | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "Idle Walk" - }, -}; - -//========================================================= -// Ambush - monster stands in place and waits for a new -// enemy, or chance to attack an existing enemy. -//========================================================= -Task_t tlAmbush[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slAmbush[] = -{ - { - tlAmbush, - ARRAYSIZE ( tlAmbush ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED, - - 0, - "Ambush" - }, -}; - -//========================================================= -// ActiveIdle schedule - !!!BUGBUG - if this schedule doesn't -// complete on its own, the monster's HintNode will not be -// cleared, and the rest of the monster's group will avoid -// that node because they think the group member that was -// previously interrupted is still using that node to active -// idle. -///========================================================= -Task_t tlActiveIdle[] = -{ - { TASK_FIND_HINTNODE, (float)0 }, - { TASK_GET_PATH_TO_HINTNODE, (float)0 }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_HINTNODE, (float)0 }, - { TASK_PLAY_ACTIVE_IDLE, (float)0 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, - { TASK_CLEAR_HINTNODE, (float)0 }, -}; - -Schedule_t slActiveIdle[] = -{ - { - tlActiveIdle, - ARRAYSIZE( tlActiveIdle ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT | - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER, - "Active Idle" - } -}; - -//========================================================= -// Wake Schedules -//========================================================= -Task_t tlWakeAngry1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SOUND_WAKE, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, -}; - -Schedule_t slWakeAngry[] = -{ - { - tlWakeAngry1, - ARRAYSIZE ( tlWakeAngry1 ), - 0, - 0, - "Wake Angry" - } -}; - -//========================================================= -// AlertFace Schedules -//========================================================= -Task_t tlAlertFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, -}; - -Schedule_t slAlertFace[] = -{ - { - tlAlertFace1, - ARRAYSIZE ( tlAlertFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED, - 0, - "Alert Face" - }, -}; - -//========================================================= -// AlertSmallFlinch Schedule - shot, but didn't see attacker, -// flinch then face -//========================================================= -Task_t tlAlertSmallFlinch[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, - { TASK_SMALL_FLINCH, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_ALERT_FACE }, -}; - -Schedule_t slAlertSmallFlinch[] = -{ - { - tlAlertSmallFlinch, - ARRAYSIZE ( tlAlertSmallFlinch ), - 0, - 0, - "Alert Small Flinch" - }, -}; - -//========================================================= -// AlertIdle Schedules -//========================================================= -Task_t tlAlertStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)20 }, - { TASK_SUGGEST_STATE, (float)MONSTERSTATE_IDLE }, -}; - -Schedule_t slAlertStand[] = -{ - { - tlAlertStand1, - ARRAYSIZE ( tlAlertStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_SMELL | - bits_COND_SMELL_FOOD | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_PLAYER | - bits_SOUND_DANGER | - - bits_SOUND_MEAT |// scent flags - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "Alert Stand" - }, -}; - -//========================================================= -// InvestigateSound - sends a monster to the location of the -// sound that was just heard, to check things out. -//========================================================= -Task_t tlInvestigateSound[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_GET_PATH_TO_BESTSOUND, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_IDLE }, - { TASK_WAIT, (float)10 }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slInvestigateSound[] = -{ - { - tlInvestigateSound, - ARRAYSIZE ( tlInvestigateSound ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "InvestigateSound" - }, -}; - -//========================================================= -// CombatIdle Schedule -//========================================================= -Task_t tlCombatStand1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slCombatStand[] = -{ - { - tlCombatStand1, - ARRAYSIZE ( tlCombatStand1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_ATTACK, - 0, - "Combat Stand" - }, -}; - -//========================================================= -// CombatFace Schedule -//========================================================= -Task_t tlCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slCombatFace[] = -{ - { - tlCombatFace1, - ARRAYSIZE ( tlCombatFace1 ), - bits_COND_CAN_ATTACK | - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Standoff schedule. Used in combat when a monster is -// hiding in cover or the enemy has moved out of sight. -// Should we look around in this schedule? -//========================================================= -Task_t tlStandoff[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, -}; - -Schedule_t slStandoff[] = -{ - { - tlStandoff, - ARRAYSIZE ( tlStandoff ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_ENEMY_DEAD | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Standoff" - } -}; - -//========================================================= -// Arm weapon (draw gun) -//========================================================= -Task_t tlArmWeapon[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float) ACT_ARM } -}; - -Schedule_t slArmWeapon[] = -{ - { - tlArmWeapon, - ARRAYSIZE ( tlArmWeapon ), - 0, - 0, - "Arm Weapon" - } -}; - -//========================================================= -// reload schedule -//========================================================= -Task_t tlReload[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, float(ACT_RELOAD) }, -}; - -Schedule_t slReload[] = -{ - { - tlReload, - ARRAYSIZE ( tlReload ), - bits_COND_HEAVY_DAMAGE, - 0, - "Reload" - } -}; - -//========================================================= -// Attack Schedules -//========================================================= - -// primary range attack -Task_t tlRangeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slRangeAttack1[] = -{ - { - tlRangeAttack1, - ARRAYSIZE ( tlRangeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1" - }, -}; - -// secondary range attack -Task_t tlRangeAttack2[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, -}; - -Schedule_t slRangeAttack2[] = -{ - { - tlRangeAttack2, - ARRAYSIZE ( tlRangeAttack2 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack2" - }, -}; - -// primary melee attack -Task_t tlPrimaryMeleeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, -}; - -Schedule_t slPrimaryMeleeAttack[] = -{ - { - tlPrimaryMeleeAttack1, - ARRAYSIZE ( tlPrimaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - 0, - "Primary Melee Attack" - }, -}; - -// secondary melee attack -Task_t tlSecondaryMeleeAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK2, (float)0 }, -}; - -Schedule_t slSecondaryMeleeAttack[] = -{ - { - tlSecondaryMeleeAttack1, - ARRAYSIZE ( tlSecondaryMeleeAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - 0, - "Secondary Melee Attack" - }, -}; - -// special attack1 -Task_t tlSpecialAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, -}; - -Schedule_t slSpecialAttack1[] = -{ - { - tlSpecialAttack1, - ARRAYSIZE ( tlSpecialAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Special Attack1" - }, -}; - -// special attack2 -Task_t tlSpecialAttack2[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPECIAL_ATTACK2, (float)0 }, -}; - -Schedule_t slSpecialAttack2[] = -{ - { - tlSpecialAttack2, - ARRAYSIZE ( tlSpecialAttack2 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Special Attack2" - }, -}; - -// Chase enemy schedule -Task_t tlChaseEnemy1[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CHASE_ENEMY_FAILED }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slChaseEnemy[] = -{ - { - tlChaseEnemy1, - ARRAYSIZE ( tlChaseEnemy1 ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_TASK_FAILED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Chase Enemy" - }, -}; - - -// Chase enemy failure schedule -Task_t tlChaseEnemyFailed[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, -// { TASK_TURN_LEFT, (float)179 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slChaseEnemyFailed[] = -{ - { - tlChaseEnemyFailed, - ARRAYSIZE ( tlChaseEnemyFailed ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "tlChaseEnemyFailed" - }, -}; - - -//========================================================= -// small flinch, played when minor damage is taken. -//========================================================= -Task_t tlSmallFlinch[] = -{ - { TASK_REMEMBER, (float)bits_MEMORY_FLINCHED }, - { TASK_STOP_MOVING, 0 }, - { TASK_SMALL_FLINCH, 0 }, -}; - -Schedule_t slSmallFlinch[] = -{ - { - tlSmallFlinch, - ARRAYSIZE ( tlSmallFlinch ), - 0, - 0, - "Small Flinch" - }, -}; - -//========================================================= -// Die! -//========================================================= -Task_t tlDie1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, -}; - -Schedule_t slDie[] = -{ - { - tlDie1, - ARRAYSIZE( tlDie1 ), - 0, - 0, - "Die" - }, -}; - -//========================================================= -// Victory Dance -//========================================================= -Task_t tlVictoryDance[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, - { TASK_WAIT, (float)0 }, -}; - -Schedule_t slVictoryDance[] = -{ - { - tlVictoryDance, - ARRAYSIZE( tlVictoryDance ), - 0, - 0, - "Victory Dance" - }, -}; - -//========================================================= -// BarnacleVictimGrab - barnacle tongue just hit the monster, -// so play a hit animation, then play a cycling pull animation -// as the creature is hoisting the monster. -//========================================================= -Task_t tlBarnacleVictimGrab[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_HIT }, - { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_PULL }, - { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. -}; - -Schedule_t slBarnacleVictimGrab[] = -{ - { - tlBarnacleVictimGrab, - ARRAYSIZE ( tlBarnacleVictimGrab ), - 0, - 0, - "Barnacle Victim" - } -}; - -//========================================================= -// BarnacleVictimChomp - barnacle has pulled the prey to its -// mouth. Victim should play the BARNCLE_CHOMP animation -// once, then loop the BARNACLE_CHEW animation indefinitely -//========================================================= -Task_t tlBarnacleVictimChomp[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_BARNACLE_CHOMP }, - { TASK_SET_ACTIVITY, (float)ACT_BARNACLE_CHEW }, - { TASK_WAIT_INDEFINITE, (float)0 },// just cycle barnacle pull anim while barnacle hoists. -}; - -Schedule_t slBarnacleVictimChomp[] = -{ - { - tlBarnacleVictimChomp, - ARRAYSIZE ( tlBarnacleVictimChomp ), - 0, - 0, - "Barnacle Chomp" - } -}; - - -// Universal Error Schedule -Task_t tlError[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_INDEFINITE, (float)0 }, -}; - -Schedule_t slError[] = -{ - { - tlError, - ARRAYSIZE ( tlError ), - 0, - 0, - "Error" - }, -}; - -Task_t tlScriptedWalk[] = -{ - { TASK_WALK_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slWalkToScript[] = -{ - { - tlScriptedWalk, - ARRAYSIZE ( tlScriptedWalk ), - SCRIPT_BREAK_CONDITIONS, - 0, - "WalkToScript" - }, -}; - - -Task_t tlScriptedRun[] = -{ - { TASK_RUN_TO_TARGET, (float)TARGET_MOVE_SCRIPTED }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_PLANT_ON_SCRIPT, (float)0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_ENABLE_SCRIPT, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slRunToScript[] = -{ - { - tlScriptedRun, - ARRAYSIZE ( tlScriptedRun ), - SCRIPT_BREAK_CONDITIONS, - 0, - "RunToScript" - }, -}; - -Task_t tlScriptedWait[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slWaitScript[] = -{ - { - tlScriptedWait, - ARRAYSIZE ( tlScriptedWait ), - SCRIPT_BREAK_CONDITIONS, - 0, - "WaitForScript" - }, -}; - -Task_t tlScriptedFace[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_SCRIPT, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_FOR_SCRIPT, (float)0 }, - { TASK_PLAY_SCRIPT, (float)0 }, -}; - -Schedule_t slFaceScript[] = -{ - { - tlScriptedFace, - ARRAYSIZE ( tlScriptedFace ), - SCRIPT_BREAK_CONDITIONS, - 0, - "FaceScript" - }, -}; - -//========================================================= -// Cower - this is what is usually done when attempts -// to escape danger fail. -//========================================================= -Task_t tlCower[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_COWER }, -}; - -Schedule_t slCower[] = -{ - { - tlCower, - ARRAYSIZE ( tlCower ), - 0, - 0, - "Cower" - }, -}; - -//========================================================= -// move away from where you're currently standing. -//========================================================= -Task_t tlTakeCoverFromOrigin[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ORIGIN, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slTakeCoverFromOrigin[] = -{ - { - tlTakeCoverFromOrigin, - ARRAYSIZE ( tlTakeCoverFromOrigin ), - bits_COND_NEW_ENEMY, - 0, - "TakeCoverFromOrigin" - }, -}; - -//========================================================= -// hide from the loudest sound source -//========================================================= -Task_t tlTakeCoverFromBestSound[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slTakeCoverFromBestSound[] = -{ - { - tlTakeCoverFromBestSound, - ARRAYSIZE ( tlTakeCoverFromBestSound ), - bits_COND_NEW_ENEMY, - 0, - "TakeCoverFromBestSound" - }, -}; - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, -// { TASK_TURN_LEFT, (float)179 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slTakeCoverFromEnemy[] = -{ - { - tlTakeCoverFromEnemy, - ARRAYSIZE ( tlTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY, - 0, - "tlTakeCoverFromEnemy" - }, -}; - -Schedule_t *CBaseMonster::m_scheduleList[] = -{ - slIdleStand, - slIdleTrigger, - slIdleWalk, - slAmbush, - slActiveIdle, - slWakeAngry, - slAlertFace, - slAlertSmallFlinch, - slAlertStand, - slInvestigateSound, - slCombatStand, - slCombatFace, - slStandoff, - slArmWeapon, - slReload, - slRangeAttack1, - slRangeAttack2, - slPrimaryMeleeAttack, - slSecondaryMeleeAttack, - slSpecialAttack1, - slSpecialAttack2, - slChaseEnemy, - slChaseEnemyFailed, - slSmallFlinch, - slDie, - slVictoryDance, - slBarnacleVictimGrab, - slBarnacleVictimChomp, - slError, - slWalkToScript, - slRunToScript, - slWaitScript, - slFaceScript, - slCower, - slTakeCoverFromOrigin, - slTakeCoverFromBestSound, - slTakeCoverFromEnemy, - slFail -}; - -Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) -{ - return ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) ); -} - - -Schedule_t *CBaseMonster :: ScheduleInList( const char *pName, Schedule_t **pList, int listCount ) -{ - int i; - - if ( !pName ) - { - ALERT( at_console, "%s set to unnamed schedule!\n", STRING(pev->classname) ); - return NULL; - } - - - for ( i = 0; i < listCount; i++ ) - { - if ( !pList[i]->pName ) - { - ALERT( at_console, "Unnamed schedule!\n" ); - continue; - } - if ( stricmp( pName, pList[i]->pName ) == 0 ) - return pList[i]; - } - return NULL; -} - -//========================================================= -// GetScheduleOfType - returns a pointer to one of the -// monster's available schedules of the indicated type. -//========================================================= -Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) -{ -// ALERT ( at_console, "Sched Type:%d\n", Type ); - switch ( Type ) - { - // This is the schedule for scripted sequences AND scripted AI - case SCHED_AISCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } -// else -// ALERT( at_aiconsole, "Starting script %s for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - - switch ( m_pCine->m_fMoveTo ) - { - case 0: - case 4: - return slWaitScript; - case 1: - return slWalkToScript; - case 2: - return slRunToScript; - case 5: - return slFaceScript; - } - break; - } - case SCHED_IDLE_STAND: - { - if ( RANDOM_LONG(0,14) == 0 && FCanActiveIdle() ) - { - return &slActiveIdle[ 0 ]; - } - - return &slIdleStand[ 0 ]; - } - case SCHED_IDLE_WALK: - { - return &slIdleWalk[ 0 ]; - } - case SCHED_WAIT_TRIGGER: - { - return &slIdleTrigger[ 0 ]; - } - case SCHED_WAKE_ANGRY: - { - return &slWakeAngry[ 0 ]; - } - case SCHED_ALERT_FACE: - { - return &slAlertFace[ 0 ]; - } - case SCHED_ALERT_STAND: - { - return &slAlertStand[ 0 ]; - } - case SCHED_COMBAT_STAND: - { - return &slCombatStand[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slCombatFace[ 0 ]; - } - case SCHED_CHASE_ENEMY: - { - return &slChaseEnemy[ 0 ]; - } - case SCHED_CHASE_ENEMY_FAILED: - { - return &slFail[ 0 ]; - } - case SCHED_SMALL_FLINCH: - { - return &slSmallFlinch[ 0 ]; - } - case SCHED_ALERT_SMALL_FLINCH: - { - return &slAlertSmallFlinch[ 0 ]; - } - case SCHED_RELOAD: - { - return &slReload[ 0 ]; - } - case SCHED_ARM_WEAPON: - { - return &slArmWeapon[ 0 ]; - } - case SCHED_STANDOFF: - { - return &slStandoff[ 0 ]; - } - case SCHED_RANGE_ATTACK1: - { - return &slRangeAttack1[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slRangeAttack2[ 0 ]; - } - case SCHED_MELEE_ATTACK1: - { - return &slPrimaryMeleeAttack[ 0 ]; - } - case SCHED_MELEE_ATTACK2: - { - return &slSecondaryMeleeAttack[ 0 ]; - } - case SCHED_SPECIAL_ATTACK1: - { - return &slSpecialAttack1[ 0 ]; - } - case SCHED_SPECIAL_ATTACK2: - { - return &slSpecialAttack2[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slTakeCoverFromBestSound[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_ENEMY: - { - return &slTakeCoverFromEnemy[ 0 ]; - } - case SCHED_COWER: - { - return &slCower[ 0 ]; - } - case SCHED_AMBUSH: - { - return &slAmbush[ 0 ]; - } - case SCHED_BARNACLE_VICTIM_GRAB: - { - return &slBarnacleVictimGrab[ 0 ]; - } - case SCHED_BARNACLE_VICTIM_CHOMP: - { - return &slBarnacleVictimChomp[ 0 ]; - } - case SCHED_INVESTIGATE_SOUND: - { - return &slInvestigateSound[ 0 ]; - } - case SCHED_DIE: - { - return &slDie[ 0 ]; - } - case SCHED_TAKE_COVER_FROM_ORIGIN: - { - return &slTakeCoverFromOrigin[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - return &slVictoryDance[ 0 ]; - } - case SCHED_FAIL: - { - return slFail; - } - default: - { - ALERT ( at_console, "GetScheduleOfType()\nNo CASE for Schedule Type %d!\n", Type ); - - return &slIdleStand[ 0 ]; - break; - } - } - - return NULL; -} diff --git a/sdk/dlls/defaultai.h b/sdk/dlls/defaultai.h deleted file mode 100644 index 32657ab..0000000 --- a/sdk/dlls/defaultai.h +++ /dev/null @@ -1,98 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef DEFAULTAI_H -#define DEFAULTAI_H - -//========================================================= -// Failed -//========================================================= -extern Schedule_t slFail[]; - -//========================================================= -// Idle Schedules -//========================================================= -extern Schedule_t slIdleStand[]; -extern Schedule_t slIdleTrigger[]; -extern Schedule_t slIdleWalk[]; - -//========================================================= -// Wake Schedules -//========================================================= -extern Schedule_t slWakeAngry[]; - -//========================================================= -// AlertTurn Schedules -//========================================================= -extern Schedule_t slAlertFace[]; - -//========================================================= -// AlertIdle Schedules -//========================================================= -extern Schedule_t slAlertStand[]; - -//========================================================= -// CombatIdle Schedule -//========================================================= -extern Schedule_t slCombatStand[]; - -//========================================================= -// CombatFace Schedule -//========================================================= -extern Schedule_t slCombatFace[]; - -//========================================================= -// reload schedule -//========================================================= -extern Schedule_t slReload[]; - -//========================================================= -// Attack Schedules -//========================================================= - -extern Schedule_t slRangeAttack1[]; -extern Schedule_t slRangeAttack2[]; - -extern Schedule_t slTakeCoverFromBestSound[]; - -// primary melee attack -extern Schedule_t slMeleeAttack[]; - -// Chase enemy schedule -extern Schedule_t slChaseEnemy[]; - -//========================================================= -// small flinch, used when a relatively minor bit of damage -// is inflicted. -//========================================================= -extern Schedule_t slSmallFlinch[]; - -//========================================================= -// Die! -//========================================================= -extern Schedule_t slDie[]; - -//========================================================= -// Universal Error Schedule -//========================================================= -extern Schedule_t slError[]; - -//========================================================= -// Scripted sequences -//========================================================= -extern Schedule_t slWalkToScript[]; -extern Schedule_t slRunToScript[]; -extern Schedule_t slWaitScript[]; - -#endif // DEFAULTAI_H diff --git a/sdk/dlls/doors.cpp b/sdk/dlls/doors.cpp deleted file mode 100644 index bbfefae..0000000 --- a/sdk/dlls/doors.cpp +++ /dev/null @@ -1,1052 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== doors.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "doors.h" - - -extern void SetMovedir(entvars_t* ev); - -#define noiseMoving noise1 -#define noiseArrived noise2 - -class CBaseDoor : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - virtual void KeyValue( KeyValueData *pkvd ); - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void Blocked( CBaseEntity *pOther ); - - - virtual int ObjectCaps( void ) - { - if (pev->spawnflags & SF_ITEM_USE_ONLY) - return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; - else - return (CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); - }; - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - virtual void SetToggleState( int state ); - - // used to selectivly override defaults - void EXPORT DoorTouch( CBaseEntity *pOther ); - - // local functions - int DoorActivate( ); - void EXPORT DoorGoUp( void ); - void EXPORT DoorGoDown( void ); - void EXPORT DoorHitTop( void ); - void EXPORT DoorHitBottom( void ); - - BYTE m_bHealthValue;// some doors are medi-kit doors, they give players health - - BYTE m_bMoveSnd; // sound a door makes while moving - BYTE m_bStopSnd; // sound a door makes when it stops - - locksound_t m_ls; // door lock sounds - - BYTE m_bLockedSound; // ordinals from entity selection - BYTE m_bLockedSentence; - BYTE m_bUnlockedSound; - BYTE m_bUnlockedSentence; -}; - - -TYPEDESCRIPTION CBaseDoor::m_SaveData[] = -{ - DEFINE_FIELD( CBaseDoor, m_bHealthValue, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bStopSnd, FIELD_CHARACTER ), - - DEFINE_FIELD( CBaseDoor, m_bLockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bLockedSentence, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSound, FIELD_CHARACTER ), - DEFINE_FIELD( CBaseDoor, m_bUnlockedSentence, FIELD_CHARACTER ), - -}; - -IMPLEMENT_SAVERESTORE( CBaseDoor, CBaseToggle ); - - -#define DOOR_SENTENCEWAIT 6 -#define DOOR_SOUNDWAIT 3 -#define BUTTON_SOUNDWAIT 0.5 - -// play door or button locked or unlocked sounds. -// pass in pointer to valid locksound struct. -// if flocked is true, play 'door is locked' sound, -// otherwise play 'door is unlocked' sound -// NOTE: this routine is shared by doors and buttons - -void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton) -{ - // LOCKED SOUND - - // CONSIDER: consolidate the locksound_t struct (all entries are duplicates for lock/unlock) - // CONSIDER: and condense this code. - float flsoundwait; - - if (fbutton) - flsoundwait = BUTTON_SOUNDWAIT; - else - flsoundwait = DOOR_SOUNDWAIT; - - if (flocked) - { - int fplaysound = (pls->sLockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sLockedSentence && !pls->bEOFLocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // if there is a locked sound, and we've debounced, play sound - if (fplaysound) - { - // play 'door locked' sound - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sLockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // if there is a sentence, we've not played all in list, and we've debounced, play sound - if (fplaysentence) - { - // play next 'door locked' sentence in group - int iprev = pls->iLockedSentence; - - pls->iLockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sLockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iLockedSentence, FALSE); - pls->iUnlockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFLocked = (iprev == pls->iLockedSentence); - - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } - else - { - // UNLOCKED SOUND - - int fplaysound = (pls->sUnlockedSound && gpGlobals->time > pls->flwaitSound); - int fplaysentence = (pls->sUnlockedSentence && !pls->bEOFUnlocked && gpGlobals->time > pls->flwaitSentence); - float fvol; - - // if playing both sentence and sound, lower sound volume so we hear sentence - if (fplaysound && fplaysentence) - fvol = 0.25; - else - fvol = 1.0; - - // play 'door unlocked' sound if set - if (fplaysound) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, (char*)STRING(pls->sUnlockedSound), fvol, ATTN_NORM); - pls->flwaitSound = gpGlobals->time + flsoundwait; - } - - // play next 'door unlocked' sentence in group - if (fplaysentence) - { - int iprev = pls->iUnlockedSentence; - - pls->iUnlockedSentence = SENTENCEG_PlaySequentialSz(ENT(pev), STRING(pls->sUnlockedSentence), - 0.85, ATTN_NORM, 0, 100, pls->iUnlockedSentence, FALSE); - pls->iLockedSentence = 0; - - // make sure we don't keep calling last sentence in list - pls->bEOFUnlocked = (iprev == pls->iUnlockedSentence); - pls->flwaitSentence = gpGlobals->time + DOOR_SENTENCEWAIT; - } - } -} - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "skin"))//skin is used for content type - { - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { - m_bHealthValue = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sound")) - { - m_bLockedSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "locked_sentence")) - { - m_bLockedSentence = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sound")) - { - m_bUnlockedSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "unlocked_sentence")) - { - m_bUnlockedSentence = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "WaveHeight")) - { - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK TOGGLE -if two doors touch, they are assumed to be connected and operate as a unit. - -TOGGLE causes the door to wait in both the start and end states for a trigger event. - -START_OPEN causes the door to move to its destination when spawned, and operate in reverse. -It is used to temporarily or permanently close off an area when triggered (not usefull for -touch or takedamage doors). - -"angle" determines the opening direction -"targetname" if set, no touch field will be spawned and a remote button or trigger - field activates the door. -"health" if set, door must be shot open -"speed" movement speed (100 default) -"wait" wait before returning (3 default, -1 = never return) -"lip" lip remaining at end of move (8 default) -"dmg" damage to inflict when blocked (2 default) -"sounds" -0) no sound -1) stone -2) base -3) stone chain -4) screechy metal -*/ - -LINK_ENTITY_TO_CLASS( func_door, CBaseDoor ); -// -// func_water - same as a door. -// -LINK_ENTITY_TO_CLASS( func_water, CBaseDoor ); - - -void CBaseDoor::Spawn( ) -{ - Precache(); - SetMovedir (pev); - - if ( pev->skin == 0 ) - {//normal door - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - } - else - {// special contents - pev->solid = SOLID_NOT; - SetBits( pev->spawnflags, SF_DOOR_SILENT ); // water is silent for now - } - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - - m_toggle_state = TS_AT_BOTTOM; - - // if the door is flagged for USE button activation only, use NULL touch function - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch( &CBaseDoor::DoorTouch ); -} - - -void CBaseDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - UTIL_SetOrigin( pev, m_vecPosition2 ); - else - UTIL_SetOrigin( pev, m_vecPosition1 ); -} - - -void CBaseDoor::Precache( void ) -{ - const char *pszSound; - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - case 9: - PRECACHE_SOUND ("doors/doormove9.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove9.wav"); - break; - case 10: - PRECACHE_SOUND ("doors/doormove10.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove10.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } - -// set the door's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doorstop1.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doorstop2.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doorstop3.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doorstop4.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doorstop5.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doorstop6.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doorstop7.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doorstop8.wav"); - pev->noiseArrived = ALLOC_STRING("doors/doorstop8.wav"); - break; - default: - pev->noiseArrived = ALLOC_STRING("common/null.wav"); - break; - } - - // get door button sounds, for doors which are directly 'touched' to open - - if (m_bLockedSound) - { - pszSound = ButtonSound( (int)m_bLockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sLockedSound = ALLOC_STRING(pszSound); - } - - if (m_bUnlockedSound) - { - pszSound = ButtonSound( (int)m_bUnlockedSound ); - PRECACHE_SOUND(pszSound); - m_ls.sUnlockedSound = ALLOC_STRING(pszSound); - } - - // get sentence group names, for doors which are directly 'touched' to open - - switch (m_bLockedSentence) - { - case 1: m_ls.sLockedSentence = ALLOC_STRING("NA"); break; // access denied - case 2: m_ls.sLockedSentence = ALLOC_STRING("ND"); break; // security lockout - case 3: m_ls.sLockedSentence = ALLOC_STRING("NF"); break; // blast door - case 4: m_ls.sLockedSentence = ALLOC_STRING("NFIRE"); break; // fire door - case 5: m_ls.sLockedSentence = ALLOC_STRING("NCHEM"); break; // chemical door - case 6: m_ls.sLockedSentence = ALLOC_STRING("NRAD"); break; // radiation door - case 7: m_ls.sLockedSentence = ALLOC_STRING("NCON"); break; // gen containment - case 8: m_ls.sLockedSentence = ALLOC_STRING("NH"); break; // maintenance door - case 9: m_ls.sLockedSentence = ALLOC_STRING("NG"); break; // broken door - - default: m_ls.sLockedSentence = 0; break; - } - - switch (m_bUnlockedSentence) - { - case 1: m_ls.sUnlockedSentence = ALLOC_STRING("EA"); break; // access granted - case 2: m_ls.sUnlockedSentence = ALLOC_STRING("ED"); break; // security door - case 3: m_ls.sUnlockedSentence = ALLOC_STRING("EF"); break; // blast door - case 4: m_ls.sUnlockedSentence = ALLOC_STRING("EFIRE"); break; // fire door - case 5: m_ls.sUnlockedSentence = ALLOC_STRING("ECHEM"); break; // chemical door - case 6: m_ls.sUnlockedSentence = ALLOC_STRING("ERAD"); break; // radiation door - case 7: m_ls.sUnlockedSentence = ALLOC_STRING("ECON"); break; // gen containment - case 8: m_ls.sUnlockedSentence = ALLOC_STRING("EH"); break; // maintenance door - - default: m_ls.sUnlockedSentence = 0; break; - } -} - -// -// Doors not tied to anything (e.g. button, another door) can be touched, to make them activate. -// -void CBaseDoor::DoorTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // Ignore touches by anything but players - if (!FClassnameIs(pevToucher, "player")) - return; - - // If door has master, and it's not ready to trigger, - // play 'locked' sound - - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, pOther)) - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - - // If door is somebody's target, then touching does nothing. - // You have to activate the owner (e.g. button). - - if (!FStringNull(pev->targetname)) - { - // play locked sound - PlayLockSounds(pev, &m_ls, TRUE, FALSE); - return; - } - - m_hActivator = pOther;// remember who activated the door - - if (DoorActivate( )) - SetTouch( NULL ); // Temporarily disable the touch function, until movement is finished. -} - - -// -// Used by SUB_UseTargets, when a door is the target of a button. -// -void CBaseDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_hActivator = pActivator; - // if not ready to be used, ignore "use" command. - if (m_toggle_state == TS_AT_BOTTOM || (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP)) - DoorActivate(); -} - -// -// Causes the door to "do its thing", i.e. start moving, and cascade activation. -// -int CBaseDoor::DoorActivate( ) -{ - if (!UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return 0; - - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN) && m_toggle_state == TS_AT_TOP) - {// door should close - DoorGoDown(); - } - else - {// door should open - - if ( m_hActivator != 0 && m_hActivator->IsPlayer() ) - {// give health if player opened the door (medikit) - // VARS( m_eoActivator )->health += m_bHealthValue; - - m_hActivator->TakeHealth( m_bHealthValue, DMG_GENERIC ); - - } - - // play door unlock sounds - PlayLockSounds(pev, &m_ls, FALSE, FALSE); - - DoorGoUp(); - } - - return 1; -} - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -// -// Starts the door going to its "up" position (simply ToggleData->vecPosition2). -// -void CBaseDoor::DoorGoUp( void ) -{ - entvars_t *pevActivator; - - // It could be going-down, if blocked. - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - - // emit door moving and stop sounds on CHAN_STATIC so that the multicast doesn't - // filter them out and leave a client stuck with looping door sounds! - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - } - - m_toggle_state = TS_GOING_UP; - - SetMoveDone( &CBaseDoor::DoorHitTop ); - if ( FClassnameIs(pev, "func_door_rotating")) // !!! BUGBUG Triggered doors don't work with this yet - { - float sign = 1.0; - - if ( m_hActivator != 0 ) - { - pevActivator = m_hActivator->pev; - - if ( !FBitSet( pev->spawnflags, SF_DOOR_ONEWAY ) && pev->movedir.y ) // Y axis rotation, move away from the player - { - Vector vec = pevActivator->origin - pev->origin; - Vector angles = pevActivator->angles; - angles.x = 0; - angles.z = 0; - UTIL_MakeVectors (angles); - // Vector vnext = (pevToucher->origin + (pevToucher->velocity * 10)) - pev->origin; - UTIL_MakeVectors ( pevActivator->angles ); - Vector vnext = (pevActivator->origin + (gpGlobals->v_forward * 10)) - pev->origin; - if ( (vec.x*vnext.y - vec.y*vnext.x) < 0 ) - sign = -1.0; - } - } - AngularMove(m_vecAngle2*sign, pev->speed); - } - else - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// The door has reached the "up" position. Either go back down, or wait for another activation. -// -void CBaseDoor::DoorHitTop( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - // toggle-doors don't come down automatically, they wait for refire. - if (FBitSet(pev->spawnflags, SF_DOOR_NO_AUTO_RETURN)) - { - // Re-instate touch method, movement is complete - if ( !FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - SetTouch( &CBaseDoor::DoorTouch ); - } - else - { - // In flWait seconds, DoorGoDown will fire, unless wait is -1, then door stays open - pev->nextthink = pev->ltime + m_flWait; - SetThink( &CBaseDoor::DoorGoDown ); - - if ( m_flWait == -1 ) - { - pev->nextthink = -1; - } - } - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && (pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished -} - - -// -// Starts the door going to its "down" position (simply ToggleData->vecPosition1). -// -void CBaseDoor::DoorGoDown( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - if ( m_toggle_state != TS_GOING_UP && m_toggle_state != TS_GOING_DOWN ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - } - -#ifdef DOOR_ASSERT - ASSERT(m_toggle_state == TS_AT_TOP); -#endif // DOOR_ASSERT - m_toggle_state = TS_GOING_DOWN; - - SetMoveDone( &CBaseDoor::DoorHitBottom ); - if ( FClassnameIs(pev, "func_door_rotating"))//rotating door - AngularMove( m_vecAngle1, pev->speed); - else - LinearMove( m_vecPosition1, pev->speed); -} - -// -// The door has reached the "down" position. Back to quiescence. -// -void CBaseDoor::DoorHitBottom( void ) -{ - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - { - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); - } - - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; - - // Re-instate touch method, cycle is complete - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - {// use only door - SetTouch ( NULL ); - } - else // touchable door - SetTouch( &CBaseDoor::DoorTouch ); - - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); // this isn't finished - - // Fire the close target (if startopen is set, then "top" is closed) - netname is the close target - if ( pev->netname && !(pev->spawnflags & SF_DOOR_START_OPEN) ) - FireTargets( STRING(pev->netname), m_hActivator, this, USE_TOGGLE, 0 ); -} - -void CBaseDoor::Blocked( CBaseEntity *pOther ) -{ - edict_t *pentTarget = NULL; - CBaseDoor *pDoor = NULL; - - - // Hurt the blocker a little. - if ( pev->dmg ) - pOther->TakeDamage( pev, pev, pev->dmg, DMG_CRUSH ); - - // if a door has a negative wait, it would never come back if blocked, - // so let it just squash the object to death real fast - - if (m_flWait >= 0) - { - if (m_toggle_state == TS_GOING_DOWN) - { - DoorGoUp(); - } - else - { - DoorGoDown(); - } - } - - // Block all door pieces with the same targetname here. - if ( !FStringNull ( pev->targetname ) ) - { - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->targetname)); - - if ( VARS( pentTarget ) != pev ) - { - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs ( pentTarget, "func_door" ) || FClassnameIs ( pentTarget, "func_door_rotating" ) ) - { - - pDoor = GetClassPtr( (CBaseDoor *) VARS(pentTarget) ); - - if ( pDoor->m_flWait >= 0) - { - if (pDoor->pev->velocity == pev->velocity && pDoor->pev->avelocity == pev->velocity) - { - // this is the most hacked, evil, bastardized thing I've ever seen. kjb - if ( FClassnameIs ( pentTarget, "func_door" ) ) - {// set origin to realign normal doors - pDoor->pev->origin = pev->origin; - pDoor->pev->velocity = g_vecZero;// stop! - } - else - {// set angles to realign rotating doors - pDoor->pev->angles = pev->angles; - pDoor->pev->avelocity = g_vecZero; - } - } - - if ( !FBitSet( pev->spawnflags, SF_DOOR_SILENT ) ) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - - if ( pDoor->m_toggle_state == TS_GOING_DOWN) - pDoor->DoorGoUp(); - else - pDoor->DoorGoDown(); - } - } - } - } - } -} - - -/*QUAKED FuncRotDoorSpawn (0 .5 .8) ? START_OPEN REVERSE -DOOR_DONT_LINK TOGGLE X_AXIS Y_AXIS -if two doors touch, they are assumed to be connected and operate as -a unit. - -TOGGLE causes the door to wait in both the start and end states for -a trigger event. - -START_OPEN causes the door to move to its destination when spawned, -and operate in reverse. It is used to temporarily or permanently -close off an area when triggered (not usefull for touch or -takedamage doors). - -You need to have an origin brush as part of this entity. The -center of that brush will be -the point around which it is rotated. It will rotate around the Z -axis by default. You can -check either the X_AXIS or Y_AXIS box to change that. - -"distance" is how many degrees the door will be rotated. -"speed" determines how fast the door moves; default value is 100. - -REVERSE will cause the door to rotate in the opposite direction. - -"angle" determines the opening direction -"targetname" if set, no touch field will be spawned and a remote -button or trigger field activates the door. -"health" if set, door must be shot open -"speed" movement speed (100 default) -"wait" wait before returning (3 default, -1 = never return) -"dmg" damage to inflict when blocked (2 default) -"sounds" -0) no sound -1) stone -2) base -3) stone chain -4) screechy metal -*/ -class CRotDoor : public CBaseDoor -{ -public: - void Spawn( void ); - virtual void SetToggleState( int state ); -}; - -LINK_ENTITY_TO_CLASS( func_door_rotating, CRotDoor ); - - -void CRotDoor::Spawn( void ) -{ - Precache(); - // set the axis of rotation - CBaseToggle::AxisDir( pev ); - - // check for clockwise rotation - if ( FBitSet (pev->spawnflags, SF_DOOR_ROTATE_BACKWARDS) ) - pev->movedir = pev->movedir * -1; - - //m_flWait = 2; who the hell did this? (sjb) - m_vecAngle1 = pev->angles; - m_vecAngle2 = pev->angles + pev->movedir * m_flMoveDistance; - - ASSERTSZ(m_vecAngle1 != m_vecAngle2, "rotating door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - pev->movetype = MOVETYPE_PUSH; - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - -// DOOR_START_OPEN is to allow an entity to be lighted in the closed position -// but spawn in the open position - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2, invert movement direction - pev->angles = m_vecAngle2; - Vector vecSav = m_vecAngle1; - m_vecAngle2 = m_vecAngle1; - m_vecAngle1 = vecSav; - pev->movedir = pev->movedir * -1; - } - - m_toggle_state = TS_AT_BOTTOM; - - if ( FBitSet ( pev->spawnflags, SF_DOOR_USE_ONLY ) ) - { - SetTouch ( NULL ); - } - else // touchable button - SetTouch( &CRotDoor::DoorTouch ); -} - - -void CRotDoor :: SetToggleState( int state ) -{ - if ( state == TS_AT_TOP ) - pev->angles = m_vecAngle2; - else - pev->angles = m_vecAngle1; - - UTIL_SetOrigin( pev, pev->origin ); -} - - -class CMomentaryDoor : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void EXPORT DoorMoveDone( void ); - - BYTE m_bMoveSnd; // sound a door makes while moving -}; - -LINK_ENTITY_TO_CLASS( momentary_door, CMomentaryDoor ); - -TYPEDESCRIPTION CMomentaryDoor::m_SaveData[] = -{ - DEFINE_FIELD( CMomentaryDoor, m_bMoveSnd, FIELD_CHARACTER ), -}; - -IMPLEMENT_SAVERESTORE( CMomentaryDoor, CBaseToggle ); - -void CMomentaryDoor::Spawn( void ) -{ - SetMovedir (pev); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if (pev->speed == 0) - pev->speed = 100; - if (pev->dmg == 0) - pev->dmg = 2; - - m_vecPosition1 = pev->origin; - // Subtract 2 from size because the engine expands bboxes by 1 in all directions making the size too big - m_vecPosition2 = m_vecPosition1 + (pev->movedir * (fabs( pev->movedir.x * (pev->size.x-2) ) + fabs( pev->movedir.y * (pev->size.y-2) ) + fabs( pev->movedir.z * (pev->size.z-2) ) - m_flLip)); - ASSERTSZ(m_vecPosition1 != m_vecPosition2, "door start/end positions are equal"); - - if ( FBitSet (pev->spawnflags, SF_DOOR_START_OPEN) ) - { // swap pos1 and pos2, put door at pos2 - UTIL_SetOrigin(pev, m_vecPosition2); - m_vecPosition2 = m_vecPosition1; - m_vecPosition1 = pev->origin; - } - SetTouch( NULL ); - - Precache(); -} - -void CMomentaryDoor::Precache( void ) -{ - -// set the door's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("doors/doormove1.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove1.wav"); - break; - case 2: - PRECACHE_SOUND ("doors/doormove2.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove2.wav"); - break; - case 3: - PRECACHE_SOUND ("doors/doormove3.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove3.wav"); - break; - case 4: - PRECACHE_SOUND ("doors/doormove4.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove4.wav"); - break; - case 5: - PRECACHE_SOUND ("doors/doormove5.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove5.wav"); - break; - case 6: - PRECACHE_SOUND ("doors/doormove6.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove6.wav"); - break; - case 7: - PRECACHE_SOUND ("doors/doormove7.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove7.wav"); - break; - case 8: - PRECACHE_SOUND ("doors/doormove8.wav"); - pev->noiseMoving = ALLOC_STRING("doors/doormove8.wav"); - break; - default: - pev->noiseMoving = ALLOC_STRING("common/null.wav"); - break; - } -} - -void CMomentaryDoor::KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { -// m_bStopSnd = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "healthvalue")) - { -// m_bHealthValue = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) // Momentary buttons will pass down a float in here - return; - - if ( value > 1.0 ) - value = 1.0; - if ( value < 0.0 ) - value = 0.0; - - Vector move = m_vecPosition1 + (value * (m_vecPosition2 - m_vecPosition1)); - - Vector delta = move - pev->origin; - //float speed = delta.Length() * 10; - float speed = delta.Length() / 0.1; // move there in 0.1 sec - if ( speed == 0 ) - return; - - // This entity only thinks when it moves, so if it's thinking, it's in the process of moving - // play the sound when it starts moving (not yet thinking) - if ( pev->nextthink < pev->ltime || pev->nextthink == 0 ) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving), 1, ATTN_NORM); - // If we already moving to designated point, return - else if (move == m_vecFinalDest) - return; - - SetMoveDone( &CMomentaryDoor::DoorMoveDone ); - LinearMove( move, speed ); -} - -// -// The door has reached needed position. -// -void CMomentaryDoor::DoorMoveDone( void ) -{ - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMoving) ); - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseArrived), 1, ATTN_NORM); -} diff --git a/sdk/dlls/doors.h b/sdk/dlls/doors.h deleted file mode 100644 index 8008861..0000000 --- a/sdk/dlls/doors.h +++ /dev/null @@ -1,33 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef DOORS_H -#define DOORS_H - -// doors -#define SF_DOOR_ROTATE_Y 0 -#define SF_DOOR_START_OPEN 1 -#define SF_DOOR_ROTATE_BACKWARDS 2 -#define SF_DOOR_PASSABLE 8 -#define SF_DOOR_ONEWAY 16 -#define SF_DOOR_NO_AUTO_RETURN 32 -#define SF_DOOR_ROTATE_Z 64 -#define SF_DOOR_ROTATE_X 128 -#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button. -#define SF_DOOR_NOMONSTERS 512 // Monster can't open -#define SF_DOOR_SILENT 0x80000000 - - - -#endif //DOORS_H diff --git a/sdk/dlls/effects.cpp b/sdk/dlls/effects.cpp deleted file mode 100644 index 2f5e86a..0000000 --- a/sdk/dlls/effects.cpp +++ /dev/null @@ -1,2268 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "customentity.h" -#include "effects.h" -#include "weapons.h" -#include "decals.h" -#include "func_break.h" -#include "shake.h" - -#define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired - -#define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. - - -// Lightning target, just alias landmark -LINK_ENTITY_TO_CLASS( info_target, CPointEntity ); - - -class CBubbling : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - void EXPORT FizzThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - int m_density; - int m_frequency; - int m_bubbleModel; - int m_state; -}; - -LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling ); - -TYPEDESCRIPTION CBubbling::m_SaveData[] = -{ - DEFINE_FIELD( CBubbling, m_density, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_frequency, FIELD_INTEGER ), - DEFINE_FIELD( CBubbling, m_state, FIELD_INTEGER ), - // Let spawn restore this! - // DEFINE_FIELD( CBubbling, m_bubbleModel, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CBubbling, CBaseEntity ); - - -#define SF_BUBBLES_STARTOFF 0x0001 - -void CBubbling::Spawn( void ) -{ - Precache( ); - SET_MODEL( ENT(pev), STRING(pev->model) ); // Set size - - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - int speed = pev->speed > 0 ? static_cast(pev->speed) : static_cast(-pev->speed); - - // HACKHACK!!! - Speed in rendercolor - pev->rendercolor.x = speed >> 8; - pev->rendercolor.y = speed & 255; - pev->rendercolor.z = (pev->speed < 0) ? 1 : 0; - - - if ( !(pev->spawnflags & SF_BUBBLES_STARTOFF) ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 2.0; - m_state = 1; - } - else - m_state = 0; -} - -void CBubbling::Precache( void ) -{ - m_bubbleModel = PRECACHE_MODEL("sprites/bubble.spr"); // Precache bubble sprite -} - - -void CBubbling::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( ShouldToggle( useType, m_state ) ) - m_state = !m_state; - - if ( m_state ) - { - SetThink( &CBubbling::FizzThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - SetThink( NULL ); - pev->nextthink = 0; - } -} - - -void CBubbling::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "density")) - { - m_density = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - m_frequency = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "current")) - { - pev->speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CBubbling::FizzThink( void ) -{ - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, VecBModelOrigin(pev) ); - WRITE_BYTE( TE_FIZZ ); - WRITE_SHORT( (short)ENTINDEX( edict() ) ); - WRITE_SHORT( (short)m_bubbleModel ); - WRITE_BYTE( m_density ); - MESSAGE_END(); - - if ( m_frequency > 19 ) - pev->nextthink = gpGlobals->time + 0.5; - else - pev->nextthink = gpGlobals->time + 2.5 - (0.1 * m_frequency); -} - -// -------------------------------------------------- -// -// Beams -// -// -------------------------------------------------- - -LINK_ENTITY_TO_CLASS( beam, CBeam ); - -void CBeam::Spawn( void ) -{ - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); -} - -void CBeam::Precache( void ) -{ - if ( pev->owner ) - SetStartEntity( ENTINDEX( pev->owner ) ); - if ( pev->aiment ) - SetEndEntity( ENTINDEX( pev->aiment ) ); -} - -void CBeam::SetStartEntity( int entityIndex ) -{ - pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); - pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - -void CBeam::SetEndEntity( int entityIndex ) -{ - pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); - pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); -} - - -// These don't take attachments into account -const Vector &CBeam::GetStartPos( void ) -{ - if ( GetType() == BEAM_ENTS ) - { - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); - return pent->v.origin; - } - return pev->origin; -} - - -const Vector &CBeam::GetEndPos( void ) -{ - int type = GetType(); - if ( type == BEAM_POINTS || type == BEAM_HOSE ) - { - return pev->angles; - } - - edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); - if ( pent ) - return pent->v.origin; - return pev->angles; -} - - -CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) -{ - // Create a new entity with CBeam private data - CBeam *pBeam = GetClassPtr( (CBeam *)NULL ); - pBeam->pev->classname = MAKE_STRING("beam"); - - pBeam->BeamInit( pSpriteName, width ); - - return pBeam; -} - - -void CBeam::BeamInit( const char *pSpriteName, int width ) -{ - pev->flags |= FL_CUSTOMENTITY; - SetColor( 255, 255, 255 ); - SetBrightness( 255 ); - SetNoise( 0 ); - SetFrame( 0 ); - SetScrollRate( 0 ); - pev->model = MAKE_STRING( pSpriteName ); - SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); - SetWidth( width ); - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; -} - - -void CBeam::PointsInit( const Vector &start, const Vector &end ) -{ - SetType( BEAM_POINTS ); - SetStartPos( start ); - SetEndPos( end ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::HoseInit( const Vector &start, const Vector &direction ) -{ - SetType( BEAM_HOSE ); - SetStartPos( start ); - SetEndPos( direction ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::PointEntInit( const Vector &start, int endIndex ) -{ - SetType( BEAM_ENTPOINT ); - SetStartPos( start ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - -void CBeam::EntsInit( int startIndex, int endIndex ) -{ - SetType( BEAM_ENTS ); - SetStartEntity( startIndex ); - SetEndEntity( endIndex ); - SetStartAttachment( 0 ); - SetEndAttachment( 0 ); - RelinkBeam(); -} - - -void CBeam::RelinkBeam( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->mins.x = min( startPos.x, endPos.x ); - pev->mins.y = min( startPos.y, endPos.y ); - pev->mins.z = min( startPos.z, endPos.z ); - pev->maxs.x = max( startPos.x, endPos.x ); - pev->maxs.y = max( startPos.y, endPos.y ); - pev->maxs.z = max( startPos.z, endPos.z ); - pev->mins = pev->mins - pev->origin; - pev->maxs = pev->maxs - pev->origin; - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); -} - -#if 0 -void CBeam::SetObjectCollisionBox( void ) -{ - const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); - - pev->absmin.x = min( startPos.x, endPos.x ); - pev->absmin.y = min( startPos.y, endPos.y ); - pev->absmin.z = min( startPos.z, endPos.z ); - pev->absmax.x = max( startPos.x, endPos.x ); - pev->absmax.y = max( startPos.y, endPos.y ); - pev->absmax.z = max( startPos.z, endPos.z ); -} -#endif - - -void CBeam::TriggerTouch( CBaseEntity *pOther ) -{ - if ( pOther->pev->flags & (FL_CLIENT | FL_MONSTER) ) - { - if ( pev->owner ) - { - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - pOwner->Use( pOther, this, USE_TOGGLE, 0 ); - } - ALERT( at_console, "Firing targets!!!\n" ); - } -} - - -CBaseEntity *CBeam::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - - -void CBeam::DoSparks( const Vector &start, const Vector &end ) -{ - if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) - { - if ( pev->spawnflags & SF_BEAM_SPARKSTART ) - { - UTIL_Sparks( start ); - } - if ( pev->spawnflags & SF_BEAM_SPARKEND ) - { - UTIL_Sparks( end ); - } - } -} - - -class CLightning : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Activate( void ); - - void EXPORT StrikeThink( void ); - void EXPORT DamageThink( void ); - void RandomArea( void ); - void RandomPoint( Vector &vecSrc ); - void Zap( const Vector &vecSrc, const Vector &vecDest ); - void EXPORT StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL ServerSide( void ) - { - if ( m_life == 0 && !(pev->spawnflags & SF_BEAM_RING) ) - return TRUE; - return FALSE; - } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void BeamUpdateVars( void ); - - int m_active; - int m_iszStartEntity; - int m_iszEndEntity; - float m_life; - int m_boltWidth; - int m_noiseAmplitude; - int m_brightness; - int m_speed; - float m_restrike; - int m_spriteTexture; - int m_iszSpriteName; - int m_frameStart; - - float m_radius; -}; - -LINK_ENTITY_TO_CLASS( env_lightning, CLightning ); -LINK_ENTITY_TO_CLASS( env_beam, CLightning ); - -// UNDONE: Jay -- This is only a test -#if _DEBUG -class CTripBeam : public CLightning -{ - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trip_beam, CTripBeam ); - -void CTripBeam::Spawn( void ) -{ - CLightning::Spawn(); - SetTouch( &CBeam::TriggerTouch ); - pev->solid = SOLID_TRIGGER; - RelinkBeam(); -} -#endif - - - -TYPEDESCRIPTION CLightning::m_SaveData[] = -{ - DEFINE_FIELD( CLightning, m_active, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszStartEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_iszEndEntity, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_life, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_boltWidth, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_noiseAmplitude, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_brightness, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_speed, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_restrike, FIELD_FLOAT ), - DEFINE_FIELD( CLightning, m_spriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLightning, m_frameStart, FIELD_INTEGER ), - DEFINE_FIELD( CLightning, m_radius, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CLightning, CBeam ); - - -void CLightning::Spawn( void ) -{ - if ( FStringNull( m_iszSpriteName ) ) - { - SetThink( &CLightning::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - pev->dmgtime = gpGlobals->time; - - if ( ServerSide() ) - { - SetThink( NULL ); - if ( pev->dmg > 0 ) - { - SetThink( &CLightning::DamageThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - if ( pev->targetname ) - { - if ( !(pev->spawnflags & SF_BEAM_STARTON) ) - { - pev->effects = EF_NODRAW; - m_active = 0; - pev->nextthink = 0; - } - else - m_active = 1; - - SetUse( &CLightning::ToggleUse ); - } - } - else - { - m_active = 0; - if ( !FStringNull(pev->targetname) ) - { - SetUse( &CLightning::StrikeUse ); - } - if ( FStringNull(pev->targetname) || FBitSet(pev->spawnflags, SF_BEAM_STARTON) ) - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - } -} - -void CLightning::Precache( void ) -{ - m_spriteTexture = PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); - CBeam::Precache(); -} - - -void CLightning::Activate( void ) -{ - if ( ServerSide() ) - BeamUpdateVars(); -} - - -void CLightning::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LightningStart")) - { - m_iszStartEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "LightningEnd")) - { - m_iszEndEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "life")) - { - m_life = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "BoltWidth")) - { - m_boltWidth = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - m_noiseAmplitude = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - m_speed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "StrikeTime")) - { - m_restrike = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - m_frameStart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "Radius")) - { - m_radius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -void CLightning::ToggleUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - if ( m_active ) - { - m_active = 0; - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - } - else - { - m_active = 1; - pev->effects &= ~EF_NODRAW; - DoSparks( GetStartPos(), GetEndPos() ); - if ( pev->dmg > 0 ) - { - pev->nextthink = gpGlobals->time; - pev->dmgtime = gpGlobals->time; - } - } -} - - -void CLightning::StrikeUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_active ) ) - return; - - if ( m_active ) - { - m_active = 0; - SetThink( NULL ); - } - else - { - SetThink( &CLightning::StrikeThink ); - pev->nextthink = gpGlobals->time + 0.1; - } - - if ( !FBitSet( pev->spawnflags, SF_BEAM_TOGGLE ) ) - SetUse( NULL ); -} - - -int IsPointEntity( CBaseEntity *pEnt ) -{ - if ( !pEnt->pev->modelindex ) - return 1; - if ( FClassnameIs( pEnt->pev, "info_target" ) || FClassnameIs( pEnt->pev, "info_landmark" ) || FClassnameIs( pEnt->pev, "path_corner" ) ) - return 1; - - return 0; -} - - -void CLightning::StrikeThink( void ) -{ - if ( m_life != 0 ) - { - if ( pev->spawnflags & SF_BEAM_RANDOM ) - pev->nextthink = gpGlobals->time + m_life + RANDOM_FLOAT( 0, m_restrike ); - else - pev->nextthink = gpGlobals->time + m_life + m_restrike; - } - m_active = 1; - - if (FStringNull(m_iszEndEntity)) - { - if (FStringNull(m_iszStartEntity)) - { - RandomArea( ); - } - else - { - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - if (pStart != NULL) - RandomPoint( pStart->pev->origin ); - else - ALERT( at_console, "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) ); - } - return; - } - - CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) ); - CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) ); - - if ( pStart != NULL && pEnd != NULL ) - { - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( pev->spawnflags & SF_BEAM_RING) - { - // don't work - return; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - if ( IsPointEntity( pStart ) || IsPointEntity( pEnd ) ) - { - if ( !IsPointEntity( pEnd ) ) // One point entity must be in pEnd - { - CBaseEntity *pTemp; - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - } - if ( !IsPointEntity( pStart ) ) // One sided - { - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( pStart->entindex() ); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - else - { - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( pStart->pev->origin.x); - WRITE_COORD( pStart->pev->origin.y); - WRITE_COORD( pStart->pev->origin.z); - WRITE_COORD( pEnd->pev->origin.x); - WRITE_COORD( pEnd->pev->origin.y); - WRITE_COORD( pEnd->pev->origin.z); - } - - - } - else - { - if ( pev->spawnflags & SF_BEAM_RING) - WRITE_BYTE( TE_BEAMRING ); - else - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( pStart->entindex() ); - WRITE_SHORT( pEnd->entindex() ); - } - - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( (int)pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); - DoSparks( pStart->pev->origin, pEnd->pev->origin ); - if ( pev->dmg > 0 ) - { - TraceResult tr; - UTIL_TraceLine( pStart->pev->origin, pEnd->pev->origin, dont_ignore_monsters, NULL, &tr ); - BeamDamageInstant( &tr, pev->dmg ); - } - } -} - - -void CBeam::BeamDamage( TraceResult *ptr ) -{ - RelinkBeam(); - if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) - { - CBaseEntity *pHit = CBaseEntity::Instance(ptr->pHit); - if ( pHit ) - { - ClearMultiDamage(); - pHit->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); - ApplyMultiDamage( pev, pev ); - if ( pev->spawnflags & SF_BEAM_DECALS ) - { - if ( pHit->IsBSPModel() ) - UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); - } - } - } - pev->dmgtime = gpGlobals->time; -} - - -void CLightning::DamageThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - TraceResult tr; - UTIL_TraceLine( GetStartPos(), GetEndPos(), dont_ignore_monsters, NULL, &tr ); - BeamDamage( &tr ); -} - - - -void CLightning::Zap( const Vector &vecSrc, const Vector &vecDest ) -{ -#if 1 - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_SHORT( m_spriteTexture ); - WRITE_BYTE( m_frameStart ); // framestart - WRITE_BYTE( (int)pev->framerate); // framerate - WRITE_BYTE( (int)(m_life*10.0) ); // life - WRITE_BYTE( m_boltWidth ); // width - WRITE_BYTE( m_noiseAmplitude ); // noise - WRITE_BYTE( (int)pev->rendercolor.x ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.y ); // r, g, b - WRITE_BYTE( (int)pev->rendercolor.z ); // r, g, b - WRITE_BYTE( (int)pev->renderamt ); // brightness - WRITE_BYTE( m_speed ); // speed - MESSAGE_END(); -#else - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_LIGHTNING); - WRITE_COORD(vecSrc.x); - WRITE_COORD(vecSrc.y); - WRITE_COORD(vecSrc.z); - WRITE_COORD(vecDest.x); - WRITE_COORD(vecDest.y); - WRITE_COORD(vecDest.z); - WRITE_BYTE(10); - WRITE_BYTE(50); - WRITE_BYTE(40); - WRITE_SHORT(m_spriteTexture); - MESSAGE_END(); -#endif - DoSparks( vecSrc, vecDest ); -} - -void CLightning::RandomArea( void ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecSrc = pev->origin; - - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if (tr1.flFraction == 1.0) - continue; - - Vector vecDir2; - do { - vecDir2 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - } while (DotProduct(vecDir1, vecDir2 ) > 0); - vecDir2 = vecDir2.Normalize(); - TraceResult tr2; - UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction == 1.0) - continue; - - if ((tr1.vecEndPos - tr2.vecEndPos).Length() < m_radius * 0.1) - continue; - - UTIL_TraceLine( tr1.vecEndPos, tr2.vecEndPos, ignore_monsters, ENT(pev), &tr2 ); - - if (tr2.flFraction != 1.0) - continue; - - Zap( tr1.vecEndPos, tr2.vecEndPos ); - - break; - } -} - - -void CLightning::RandomPoint( Vector &vecSrc ) -{ - int iLoops = 0; - - for (iLoops = 0; iLoops < 10; iLoops++) - { - Vector vecDir1 = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir1 = vecDir1.Normalize(); - TraceResult tr1; - UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, ignore_monsters, ENT(pev), &tr1 ); - - if ((tr1.vecEndPos - vecSrc).Length() < m_radius * 0.1) - continue; - - if (tr1.flFraction == 1.0) - continue; - - Zap( vecSrc, tr1.vecEndPos ); - break; - } -} - - - -void CLightning::BeamUpdateVars( void ) -{ - int beamType; - int pointStart, pointEnd; - - edict_t *pStart = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszStartEntity) ); - edict_t *pEnd = FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_iszEndEntity) ); - pointStart = IsPointEntity( CBaseEntity::Instance(pStart) ); - pointEnd = IsPointEntity( CBaseEntity::Instance(pEnd) ); - - pev->skin = 0; - pev->sequence = 0; - pev->rendermode = 0; - pev->flags |= FL_CUSTOMENTITY; - pev->model = m_iszSpriteName; - SetTexture( m_spriteTexture ); - - beamType = BEAM_ENTS; - if ( pointStart || pointEnd ) - { - if ( !pointStart ) // One point entity must be in pStart - { - edict_t *pTemp; - // Swap start & end - pTemp = pStart; - pStart = pEnd; - pEnd = pTemp; - int swap = pointStart; - pointStart = pointEnd; - pointEnd = swap; - } - if ( !pointEnd ) - beamType = BEAM_ENTPOINT; - else - beamType = BEAM_POINTS; - } - - SetType( beamType ); - if ( beamType == BEAM_POINTS || beamType == BEAM_ENTPOINT || beamType == BEAM_HOSE ) - { - SetStartPos( pStart->v.origin ); - if ( beamType == BEAM_POINTS || beamType == BEAM_HOSE ) - SetEndPos( pEnd->v.origin ); - else - SetEndEntity( ENTINDEX(pEnd) ); - } - else - { - SetStartEntity( ENTINDEX(pStart) ); - SetEndEntity( ENTINDEX(pEnd) ); - } - - RelinkBeam(); - - SetWidth( m_boltWidth ); - SetNoise( m_noiseAmplitude ); - SetFrame( m_frameStart ); - SetScrollRate( m_speed ); - if ( pev->spawnflags & SF_BEAM_SHADEIN ) - SetFlags( BEAM_FSHADEIN ); - else if ( pev->spawnflags & SF_BEAM_SHADEOUT ) - SetFlags( BEAM_FSHADEOUT ); -} - - -LINK_ENTITY_TO_CLASS( env_laser, CLaser ); - -TYPEDESCRIPTION CLaser::m_SaveData[] = -{ - DEFINE_FIELD( CLaser, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CLaser, m_iszSpriteName, FIELD_STRING ), - DEFINE_FIELD( CLaser, m_firePosition, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CLaser, CBeam ); - -void CLaser::Spawn( void ) -{ - if ( FStringNull( pev->model ) ) - { - SetThink( &CLaser::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; // Remove model & collisions - Precache( ); - - SetThink( &CLaser::StrikeThink ); - pev->flags |= FL_CUSTOMENTITY; - - PointsInit( pev->origin, pev->origin ); - - if ( !m_pSprite && m_iszSpriteName ) - m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), pev->origin, TRUE ); - else - m_pSprite = NULL; - - if ( m_pSprite ) - m_pSprite->SetTransparency( kRenderGlow, static_cast(pev->rendercolor.x), static_cast(pev->rendercolor.y), static_cast(pev->rendercolor.z), static_cast(pev->renderamt), static_cast(pev->renderfx) ); - - if ( pev->targetname && !(pev->spawnflags & SF_BEAM_STARTON) ) - TurnOff(); - else - TurnOn(); -} - -void CLaser::Precache( void ) -{ - pev->modelindex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - if ( m_iszSpriteName ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteName) ); -} - - -void CLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "LaserTarget")) - { - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "width")) - { - SetWidth( (int) atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "NoiseAmplitude")) - { - SetNoise( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TextureScroll")) - { - SetScrollRate( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "EndSprite")) - { - m_iszSpriteName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "framestart")) - { - pev->frame = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBeam::KeyValue( pkvd ); -} - - -int CLaser::IsOn( void ) -{ - if (pev->effects & EF_NODRAW) - return 0; - return 1; -} - - -void CLaser::TurnOff( void ) -{ - pev->effects |= EF_NODRAW; - pev->nextthink = 0; - if ( m_pSprite ) - m_pSprite->TurnOff(); -} - - -void CLaser::TurnOn( void ) -{ - pev->effects &= ~EF_NODRAW; - if ( m_pSprite ) - m_pSprite->TurnOn(); - pev->dmgtime = gpGlobals->time; - pev->nextthink = gpGlobals->time; -} - - -void CLaser::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int active = IsOn(); - - if ( !ShouldToggle( useType, active ) ) - return; - if ( active ) - { - TurnOff(); - } - else - { - TurnOn(); - } -} - - -void CLaser::FireAtPoint( TraceResult &tr ) -{ - SetEndPos( tr.vecEndPos ); - if ( m_pSprite ) - UTIL_SetOrigin( m_pSprite->pev, tr.vecEndPos ); - - BeamDamage( &tr ); - DoSparks( GetStartPos(), tr.vecEndPos ); -} - -void CLaser::StrikeThink( void ) -{ - CBaseEntity *pEnd = RandomTargetname( STRING(pev->message) ); - - if ( pEnd ) - m_firePosition = pEnd->pev->origin; - - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_firePosition, dont_ignore_monsters, NULL, &tr ); - FireAtPoint( tr ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -class CGlow : public CPointEntity -{ -public: - void Spawn( void ); - void Think( void ); - void Animate( float frames ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_lastTime; - float m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( env_glow, CGlow ); - -TYPEDESCRIPTION CGlow::m_SaveData[] = -{ - DEFINE_FIELD( CGlow, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CGlow, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGlow, CPointEntity ); - -void CGlow::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( m_maxFrame > 1.0 && pev->framerate != 0 ) - pev->nextthink = gpGlobals->time + 0.1; - - m_lastTime = gpGlobals->time; -} - - -void CGlow::Think( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - - -void CGlow::Animate( float frames ) -{ - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame + frames, m_maxFrame ); -} - - -LINK_ENTITY_TO_CLASS( env_sprite, CSprite ); - -TYPEDESCRIPTION CSprite::m_SaveData[] = -{ - DEFINE_FIELD( CSprite, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CSprite, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSprite, CPointEntity ); - -void CSprite::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - Precache(); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; - if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) - TurnOff(); - else - TurnOn(); - - // Worldcraft only sets y rotation, copy to Z - if ( pev->angles.y != 0 && pev->angles.z == 0 ) - { - pev->angles.z = pev->angles.y; - pev->angles.y = 0; - } -} - - -void CSprite::Precache( void ) -{ - PRECACHE_MODEL( (char *)STRING(pev->model) ); - - // Reset attachment after save/restore - if ( pev->aiment ) - SetAttachment( pev->aiment, pev->body ); - else - { - // Clear attachment - pev->skin = 0; - pev->body = 0; - } -} - - -void CSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) -{ - pev->model = MAKE_STRING(pSpriteName); - pev->origin = origin; - Spawn(); -} - -CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) -{ - CSprite *pSprite = GetClassPtr( (CSprite *)NULL ); - pSprite->SpriteInit( pSpriteName, origin ); - pSprite->pev->classname = MAKE_STRING("env_sprite"); - pSprite->pev->solid = SOLID_NOT; - pSprite->pev->movetype = MOVETYPE_NOCLIP; - if ( animate ) - pSprite->TurnOn(); - - return pSprite; -} - - -void CSprite::AnimateThink( void ) -{ - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - -void CSprite::AnimateUntilDead( void ) -{ - if ( gpGlobals->time > pev->dmgtime ) - UTIL_Remove(this); - else - { - AnimateThink(); - pev->nextthink = gpGlobals->time; - } -} - -void CSprite::Expand( float scaleSpeed, float fadeSpeed ) -{ - pev->speed = scaleSpeed; - pev->health = fadeSpeed; - SetThink( &CSprite::ExpandThink ); - - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; -} - - -void CSprite::ExpandThink( void ) -{ - float frametime = gpGlobals->time - m_lastTime; - pev->scale += pev->speed * frametime; - pev->renderamt -= pev->health * frametime; - if ( pev->renderamt <= 0 ) - { - pev->renderamt = 0; - UTIL_Remove( this ); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; - } -} - - -void CSprite::Animate( float frames ) -{ - pev->frame += frames; - if ( pev->frame > m_maxFrame ) - { - if ( pev->spawnflags & SF_SPRITE_ONCE ) - { - TurnOff(); - } - else - { - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame, m_maxFrame ); - } - } -} - - -void CSprite::TurnOff( void ) -{ - pev->effects = EF_NODRAW; - pev->nextthink = 0; -} - - -void CSprite::TurnOn( void ) -{ - pev->effects = 0; - if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) - { - SetThink( &CSprite::AnimateThink ); - pev->nextthink = gpGlobals->time; - m_lastTime = gpGlobals->time; - } - pev->frame = 0; -} - - -void CSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on = pev->effects != EF_NODRAW; - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - { - TurnOff(); - } - else - { - TurnOn(); - } - } -} - - -class CGibShooter : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ShootThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual CGib *CreateGib( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iGibs; - int m_iGibCapacity; - int m_iGibMaterial; - int m_iGibModelIndex; - float m_flGibVelocity; - float m_flVariance; - float m_flGibLife; -}; - -TYPEDESCRIPTION CGibShooter::m_SaveData[] = -{ - DEFINE_FIELD( CGibShooter, m_iGibs, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibCapacity, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibMaterial, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_iGibModelIndex, FIELD_INTEGER ), - DEFINE_FIELD( CGibShooter, m_flGibVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flVariance, FIELD_FLOAT ), - DEFINE_FIELD( CGibShooter, m_flGibLife, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGibShooter, CBaseDelay ); -LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter ); - - -void CGibShooter :: Precache ( void ) -{ - if ( g_Language == LANGUAGE_GERMAN ) - { - m_iGibModelIndex = PRECACHE_MODEL ("models/germanygibs.mdl"); - } - else - { - m_iGibModelIndex = PRECACHE_MODEL ("models/hgibs.mdl"); - } -} - - -void CGibShooter::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iGibs")) - { - m_iGibs = m_iGibCapacity = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVelocity")) - { - m_flGibVelocity = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flVariance")) - { - m_flVariance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flGibLife")) - { - m_flGibLife = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - { - CBaseDelay::KeyValue( pkvd ); - } -} - -void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGibShooter::ShootThink ); - pev->nextthink = gpGlobals->time; -} - -void CGibShooter::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - - if ( m_flDelay == 0 ) - { - m_flDelay = 0.1; - } - - if ( m_flGibLife == 0 ) - { - m_flGibLife = 25; - } - - SetMovedir ( pev ); - pev->body = MODEL_FRAMES( m_iGibModelIndex ); -} - - -CGib *CGibShooter :: CreateGib ( void ) -{ - if ( CVAR_GET_FLOAT("violence_hgibs") == 0 ) - return NULL; - - CGib *pGib = GetClassPtr( (CGib *)NULL ); - pGib->Spawn( "models/hgibs.mdl" ); - pGib->m_bloodColor = BLOOD_COLOR_RED; - - if ( pev->body <= 1 ) - { - ALERT ( at_aiconsole, "GibShooter Body is <= 1!\n" ); - } - - pGib->pev->body = RANDOM_LONG ( 1, pev->body - 1 );// avoid throwing random amounts of the 0th gib. (skull). - - return pGib; -} - - -void CGibShooter :: ShootThink ( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - Vector vecShootDir; - - vecShootDir = pev->movedir; - - vecShootDir = vecShootDir + gpGlobals->v_right * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_forward * RANDOM_FLOAT( -1, 1) * m_flVariance;; - vecShootDir = vecShootDir + gpGlobals->v_up * RANDOM_FLOAT( -1, 1) * m_flVariance;; - - vecShootDir = vecShootDir.Normalize(); - CGib *pGib = CreateGib(); - - if ( pGib ) - { - pGib->pev->origin = pev->origin; - pGib->pev->velocity = vecShootDir * m_flGibVelocity; - - pGib->pev->avelocity.x = RANDOM_FLOAT ( 100, 200 ); - pGib->pev->avelocity.y = RANDOM_FLOAT ( 100, 300 ); - - float thinkTime = pGib->pev->nextthink - gpGlobals->time; - - pGib->m_lifeTime = (m_flGibLife * RANDOM_FLOAT( 0.95, 1.05 )); // +/- 5% - if ( pGib->m_lifeTime < thinkTime ) - { - pGib->pev->nextthink = gpGlobals->time + pGib->m_lifeTime; - pGib->m_lifeTime = 0; - } - - } - - if ( --m_iGibs <= 0 ) - { - if ( pev->spawnflags & SF_GIBSHOOTER_REPEATABLE ) - { - m_iGibs = m_iGibCapacity; - SetThink ( NULL ); - pev->nextthink = gpGlobals->time; - } - else - { - SetThink ( &CGibShooter::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - } -} - - -class CEnvShooter : public CGibShooter -{ - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - CGib *CreateGib( void ); -}; - -LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter ); - -void CEnvShooter :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "shootmodel")) - { - pev->model = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shootsounds")) - { - int iNoise = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - switch( iNoise ) - { - case 0: - m_iGibMaterial = matGlass; - break; - case 1: - m_iGibMaterial = matWood; - break; - case 2: - m_iGibMaterial = matMetal; - break; - case 3: - m_iGibMaterial = matFlesh; - break; - case 4: - m_iGibMaterial = matRocks; - break; - - default: - case -1: - m_iGibMaterial = matNone; - break; - } - } - else - { - CGibShooter::KeyValue( pkvd ); - } -} - - -void CEnvShooter :: Precache ( void ) -{ - m_iGibModelIndex = PRECACHE_MODEL( (char *)STRING(pev->model) ); - CBreakable::MaterialSoundPrecache( (Materials)m_iGibMaterial ); -} - - -CGib *CEnvShooter :: CreateGib ( void ) -{ - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( STRING(pev->model) ); - - int bodyPart = 0; - - if ( pev->body > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = DONT_BLEED; - pGib->m_material = m_iGibMaterial; - - pGib->pev->rendermode = pev->rendermode; - pGib->pev->renderamt = pev->renderamt; - pGib->pev->rendercolor = pev->rendercolor; - pGib->pev->renderfx = pev->renderfx; - pGib->pev->scale = pev->scale; - pGib->pev->skin = pev->skin; - - return pGib; -} - - - - -class CTestEffect : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - // void KeyValue( KeyValueData *pkvd ); - void EXPORT TestThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iLoop; - int m_iBeam; - CBeam *m_pBeam[24]; - float m_flBeamTime[24]; - float m_flStartTime; -}; - - -LINK_ENTITY_TO_CLASS( test_effect, CTestEffect ); - -void CTestEffect::Spawn( void ) -{ - Precache( ); -} - -void CTestEffect::Precache( void ) -{ - PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - -void CTestEffect::TestThink( void ) -{ - int i; - float t = (gpGlobals->time - m_flStartTime); - - if (m_iBeam < 24) - { - CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.spr", 100 ); - - TraceResult tr; - - Vector vecSrc = pev->origin; - Vector vecDir = Vector( RANDOM_FLOAT( -1.0, 1.0 ), RANDOM_FLOAT( -1.0, 1.0 ),RANDOM_FLOAT( -1.0, 1.0 ) ); - vecDir = vecDir.Normalize(); - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, ignore_monsters, ENT(pev), &tr); - - pbeam->PointsInit( vecSrc, tr.vecEndPos ); - // pbeam->SetColor( 80, 100, 255 ); - pbeam->SetColor( 255, 180, 100 ); - pbeam->SetWidth( 100 ); - pbeam->SetScrollRate( 12 ); - - m_flBeamTime[m_iBeam] = gpGlobals->time; - m_pBeam[m_iBeam] = pbeam; - m_iBeam++; - -#if 0 - Vector vecMid = (vecSrc + tr.vecEndPos) * 0.5; - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecMid.x); // X - WRITE_COORD(vecMid.y); // Y - WRITE_COORD(vecMid.z); // Z - WRITE_BYTE( 20 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 100 ); // b - WRITE_BYTE( 20 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); -#endif - } - - if (t < 3.0) - { - for (i = 0; i < m_iBeam; i++) - { - t = (gpGlobals->time - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]); - m_pBeam[i]->SetBrightness( static_cast(255 * t) ); - // m_pBeam[i]->SetScrollRate( 20 * t ); - } - pev->nextthink = gpGlobals->time + 0.1; - } - else - { - for (i = 0; i < m_iBeam; i++) - { - UTIL_Remove( m_pBeam[i] ); - } - m_flStartTime = gpGlobals->time; - m_iBeam = 0; - // pev->nextthink = gpGlobals->time; - SetThink( NULL ); - } -} - - -void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CTestEffect::TestThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flStartTime = gpGlobals->time; -} - - - -// Blood effects -class CBlood : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Color( void ) { return pev->impulse; } - inline float BloodAmount( void ) { return pev->dmg; } - - inline void SetColor( int color ) { pev->impulse = color; } - inline void SetBloodAmount( float amount ) { pev->dmg = amount; } - - Vector Direction( void ); - Vector BloodPosition( CBaseEntity *pActivator ); - -private: -}; - -LINK_ENTITY_TO_CLASS( env_blood, CBlood ); - - - -#define SF_BLOOD_RANDOM 0x0001 -#define SF_BLOOD_STREAM 0x0002 -#define SF_BLOOD_PLAYER 0x0004 -#define SF_BLOOD_DECAL 0x0008 - -void CBlood::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - SetMovedir( pev ); -} - - -void CBlood::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "color")) - { - int color = atoi(pkvd->szValue); - switch( color ) - { - case 1: - SetColor( BLOOD_COLOR_YELLOW ); - break; - default: - SetColor( BLOOD_COLOR_RED ); - break; - } - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "amount")) - { - SetBloodAmount( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -Vector CBlood::Direction( void ) -{ - if ( pev->spawnflags & SF_BLOOD_RANDOM ) - return UTIL_RandomBloodVector(); - - return pev->movedir; -} - - -Vector CBlood::BloodPosition( CBaseEntity *pActivator ) -{ - if ( pev->spawnflags & SF_BLOOD_PLAYER ) - { - edict_t *pPlayer; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = pActivator->edict(); - } - else - pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - if ( pPlayer ) - return (pPlayer->v.origin + pPlayer->v.view_ofs) + Vector( RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10), RANDOM_FLOAT(-10,10) ); - } - - return pev->origin; -} - - -void CBlood::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_BLOOD_STREAM ) - UTIL_BloodStream( BloodPosition(pActivator), Direction(), (Color() == BLOOD_COLOR_RED) ? 70 : Color(), static_cast(BloodAmount()) ); - else - UTIL_BloodDrips( BloodPosition(pActivator), Direction(), Color(), static_cast(BloodAmount()) ); - - if ( pev->spawnflags & SF_BLOOD_DECAL ) - { - Vector forward = Direction(); - Vector start = BloodPosition( pActivator ); - TraceResult tr; - - UTIL_TraceLine( start, start + forward * BloodAmount() * 2, ignore_monsters, NULL, &tr ); - if ( tr.flFraction != 1.0 ) - UTIL_BloodDecalTrace( &tr, Color() ); - } -} - - - -// Screen shake -class CShake : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Amplitude( void ) { return pev->scale; } - inline float Frequency( void ) { return pev->dmg_save; } - inline float Duration( void ) { return pev->dmg_take; } - inline float Radius( void ) { return pev->dmg; } - - inline void SetAmplitude( float amplitude ) { pev->scale = amplitude; } - inline void SetFrequency( float frequency ) { pev->dmg_save = frequency; } - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetRadius( float radius ) { pev->dmg = radius; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_shake, CShake ); - -// pev->scale is amplitude -// pev->dmg_save is frequency -// pev->dmg_take is duration -// pev->dmg is radius -// radius of 0 means all players -// NOTE: UTIL_ScreenShake() will only shake players who are on the ground - -#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius -// UNDONE: These don't work yet -#define SF_SHAKE_DISRUPT 0x0002 // Disrupt controls -#define SF_SHAKE_INAIR 0x0004 // Shake players in air - -void CShake::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; - - if ( pev->spawnflags & SF_SHAKE_EVERYONE ) - pev->dmg = 0; -} - - -void CShake::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "amplitude")) - { - SetAmplitude( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "frequency")) - { - SetFrequency( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - SetRadius( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CShake::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenShake( pev->origin, Amplitude(), Frequency(), Duration(), Radius() ); -} - - -class CFade : public CPointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } -private: -}; - -LINK_ENTITY_TO_CLASS( env_fade, CFade ); - -// pev->dmg_take is duration -// pev->dmg_save is hold duration -#define SF_FADE_IN 0x0001 // Fade in, not out -#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend -#define SF_FADE_ONLYONE 0x0004 - -void CFade::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = 0; - pev->frame = 0; -} - - -void CFade::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CFade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fadeFlags = 0; - - if ( !(pev->spawnflags & SF_FADE_IN) ) - fadeFlags |= FFADE_OUT; - - if ( pev->spawnflags & SF_FADE_MODULATE ) - fadeFlags |= FFADE_MODULATE; - - if ( pev->spawnflags & SF_FADE_ONLYONE ) - { - if ( pActivator->IsNetClient() ) - { - UTIL_ScreenFade( pActivator, pev->rendercolor, Duration(), HoldTime(), static_cast(pev->renderamt), fadeFlags ); - } - } - else - { - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), static_cast(pev->renderamt), fadeFlags ); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - -class CMessage : public CPointEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); -private: -}; - -LINK_ENTITY_TO_CLASS( env_message, CMessage ); - - -void CMessage::Spawn( void ) -{ - Precache(); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - switch( pev->impulse ) - { - case 1: // Medium radius - pev->speed = ATTN_STATIC; - break; - - case 2: // Large radius - pev->speed = ATTN_NORM; - break; - - case 3: //EVERYWHERE - pev->speed = ATTN_NONE; - break; - - default: - case 0: // Small radius - pev->speed = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( pev->scale <= 0 ) - pev->scale = 1.0; -} - - -void CMessage::Precache( void ) -{ - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - -void CMessage::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "messagesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagevolume")) - { - pev->scale = atof(pkvd->szValue) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messageattenuation")) - { - pev->impulse = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pPlayer = NULL; - - if ( pev->spawnflags & SF_MESSAGE_ALL ) - UTIL_ShowMessageAll( STRING(pev->message) ); - else - { - if ( pActivator && pActivator->IsPlayer() ) - pPlayer = pActivator; - else - { - pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - if ( pPlayer ) - UTIL_ShowMessage( STRING(pev->message), pPlayer ); - } - if ( pev->noise ) - { - EMIT_SOUND( edict(), CHAN_BODY, STRING(pev->noise), pev->scale, pev->speed ); - } - if ( pev->spawnflags & SF_MESSAGE_ONCE ) - UTIL_Remove( this ); - - SUB_UseTargets( this, USE_TOGGLE, 0 ); -} - - - -//========================================================= -// FunnelEffect -//========================================================= -class CEnvFunnel : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iSprite; // Don't save, precache -}; - -void CEnvFunnel :: Precache ( void ) -{ - m_iSprite = PRECACHE_MODEL ( "sprites/flare6.spr" ); -} - -LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel ); - -void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_LARGEFUNNEL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( m_iSprite ); - - if ( pev->spawnflags & SF_FUNNEL_REVERSE )// funnel flows in reverse? - { - WRITE_SHORT( 1 ); - } - else - { - WRITE_SHORT( 0 ); - } - - - MESSAGE_END(); - - SetThink( &CEnvFunnel::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -void CEnvFunnel::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; -} - -//========================================================= -// Beverage Dispenser -// overloaded pev->frags, is now a flag for whether or not a can is stuck in the dispenser. -// overloaded pev->health, is now how many cans remain in the machine. -//========================================================= -class CEnvBeverage : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -void CEnvBeverage :: Precache ( void ) -{ - PRECACHE_MODEL( "models/can.mdl" ); - PRECACHE_SOUND( "weapons/g_bounce3.wav" ); -} - -LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage ); - -void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->frags != 0 || pev->health <= 0 ) - { - // no more cans while one is waiting in the dispenser, or if I'm out of cans. - return; - } - - CBaseEntity *pCan = CBaseEntity::Create( "item_sodacan", pev->origin, pev->angles, edict() ); - - if ( pev->skin == 6 ) - { - // random - pCan->pev->skin = RANDOM_LONG( 0, 5 ); - } - else - { - pCan->pev->skin = pev->skin; - } - - pev->frags = 1; - pev->health--; - - //SetThink (SUB_Remove); - //pev->nextthink = gpGlobals->time; -} - -void CEnvBeverage::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->frags = 0; - - if ( pev->health == 0 ) - { - pev->health = 10; - } -} - -//========================================================= -// Soda can -//========================================================= -class CItemSoda : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT CanThink ( void ); - void EXPORT CanTouch ( CBaseEntity *pOther ); -}; - -void CItemSoda :: Precache ( void ) -{ -} - -LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda ); - -void CItemSoda::Spawn( void ) -{ - Precache(); - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_TOSS; - - SET_MODEL ( ENT(pev), "models/can.mdl" ); - UTIL_SetSize ( pev, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) ); - - SetThink (&CItemSoda::CanThink); - pev->nextthink = gpGlobals->time + 0.5; -} - -void CItemSoda::CanThink ( void ) -{ - EMIT_SOUND (ENT(pev), CHAN_WEAPON, "weapons/g_bounce3.wav", 1, ATTN_NORM ); - - pev->solid = SOLID_TRIGGER; - UTIL_SetSize ( pev, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) ); - SetThink ( NULL ); - SetTouch ( &CItemSoda::CanTouch ); -} - -void CItemSoda::CanTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - // spoit sound here - - pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health. - - if ( !FNullEnt( pev->owner ) ) - { - // tell the machine the can was taken - pev->owner->v.frags = 0; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; - SetTouch ( NULL ); - SetThink ( &CItemSoda::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} diff --git a/sdk/dlls/effects.h b/sdk/dlls/effects.h deleted file mode 100644 index 185e8a7..0000000 --- a/sdk/dlls/effects.h +++ /dev/null @@ -1,209 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EFFECTS_H -#define EFFECTS_H - -#define SF_BEAM_STARTON 0x0001 -#define SF_BEAM_TOGGLE 0x0002 -#define SF_BEAM_RANDOM 0x0004 -#define SF_BEAM_RING 0x0008 -#define SF_BEAM_SPARKSTART 0x0010 -#define SF_BEAM_SPARKEND 0x0020 -#define SF_BEAM_DECALS 0x0040 -#define SF_BEAM_SHADEIN 0x0080 -#define SF_BEAM_SHADEOUT 0x0100 -#define SF_BEAM_TEMPORARY 0x8000 - -#define SF_SPRITE_STARTON 0x0001 -#define SF_SPRITE_ONCE 0x0002 -#define SF_SPRITE_TEMPORARY 0x8000 - -class CSprite : public CPointEntity -{ -public: - void Spawn( void ); - void Precache( void ); - - int ObjectCaps( void ) - { - int flags = 0; - if ( pev->spawnflags & SF_SPRITE_TEMPORARY ) - flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; - } - void EXPORT AnimateThink( void ); - void EXPORT ExpandThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Animate( float frames ); - void Expand( float scaleSpeed, float fadeSpeed ); - void SpriteInit( const char *pSpriteName, const Vector &origin ); - - inline void SetAttachment( edict_t *pEntity, int attachment ) - { - if ( pEntity ) - { - pev->skin = ENTINDEX(pEntity); - pev->body = attachment; - pev->aiment = pEntity; - pev->movetype = MOVETYPE_FOLLOW; - } - } - void TurnOff( void ); - void TurnOn( void ); - inline float Frames( void ) { return m_maxFrame; } - inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) - { - pev->rendermode = rendermode; - pev->rendercolor.x = r; - pev->rendercolor.y = g; - pev->rendercolor.z = b; - pev->renderamt = a; - pev->renderfx = fx; - } - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetScale( float scale ) { pev->scale = scale; } - inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - - inline void AnimateAndDie( float framerate ) - { - SetThink(&CSprite::AnimateUntilDead); - pev->framerate = framerate; - pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); - pev->nextthink = gpGlobals->time; - } - - void EXPORT AnimateUntilDead( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ); - -private: - - float m_lastTime; - float m_maxFrame; -}; - - -class CBeam : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - int ObjectCaps( void ) - { - int flags = 0; - if ( pev->spawnflags & SF_BEAM_TEMPORARY ) - flags = FCAP_DONT_SAVE; - return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; - } - - void EXPORT TriggerTouch( CBaseEntity *pOther ); - - // These functions are here to show the way beams are encoded as entities. - // Encoding beams as entities simplifies their management in the client/server architecture - inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); } - inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); } - inline void SetStartPos( const Vector& pos ) { pev->origin = pos; } - inline void SetEndPos( const Vector& pos ) { pev->angles = pos; } - void SetStartEntity( int entityIndex ); - void SetEndEntity( int entityIndex ); - - inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); } - inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); } - - inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } - inline void SetWidth( int width ) { pev->scale = width; } - inline void SetNoise( int amplitude ) { pev->body = amplitude; } - inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } - inline void SetFrame( float frame ) { pev->frame = frame; } - inline void SetScrollRate( int speed ) { pev->animtime = speed; } - - inline int GetType( void ) { return pev->rendermode & 0x0F; } - inline int GetFlags( void ) { return pev->rendermode & 0xF0; } - inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; } - inline int GetEndEntity( void ) { return pev->skin & 0xFFF; } - - const Vector &GetStartPos( void ); - const Vector &GetEndPos( void ); - - Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam - - inline int GetTexture( void ) { return pev->modelindex; } - inline int GetWidth( void ) { return static_cast(pev->scale); } - inline int GetNoise( void ) { return pev->body; } - // inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } - inline int GetBrightness( void ) { return static_cast(pev->renderamt); } - inline int GetFrame( void ) { return static_cast(pev->frame); } - inline int GetScrollRate( void ) { return static_cast(pev->animtime); } - - // Call after you change start/end positions - void RelinkBeam( void ); -// void SetObjectCollisionBox( void ); - - void DoSparks( const Vector &start, const Vector &end ); - CBaseEntity *RandomTargetname( const char *szName ); - void BeamDamage( TraceResult *ptr ); - // Init after BeamCreate() - void BeamInit( const char *pSpriteName, int width ); - void PointsInit( const Vector &start, const Vector &end ); - void PointEntInit( const Vector &start, int endIndex ); - void EntsInit( int startIndex, int endIndex ); - void HoseInit( const Vector &start, const Vector &direction ); - - static CBeam *BeamCreate( const char *pSpriteName, int width ); - - inline void LiveForTime( float time ) { SetThink(&CBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; } - inline void BeamDamageInstant( TraceResult *ptr, float damage ) - { - pev->dmg = damage; - pev->dmgtime = gpGlobals->time - 1; - BeamDamage(ptr); - } -}; - - -#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out -#define SF_MESSAGE_ALL 0x0002 // Send to all clients - - -class CLaser : public CBeam -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - void TurnOn( void ); - void TurnOff( void ); - int IsOn( void ); - - void FireAtPoint( TraceResult &point ); - - void EXPORT StrikeThink( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CSprite *m_pSprite; - int m_iszSpriteName; - Vector m_firePosition; -}; - -#endif //EFFECTS_H diff --git a/sdk/dlls/egon.cpp b/sdk/dlls/egon.cpp deleted file mode 100644 index 71d3609..0000000 --- a/sdk/dlls/egon.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" -#include "customentity.h" -#include "gamerules.h" - -#define EGON_PRIMARY_VOLUME 450 -#define EGON_BEAM_SPRITE "sprites/xbeam1.spr" -#define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" -#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" - -#define EGON_SWITCH_NARROW_TIME 0.75 // Time it takes to switch fire modes -#define EGON_SWITCH_WIDE_TIME 1.5 - -enum egon_e { - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -LINK_ENTITY_TO_CLASS( weapon_egon, CEgon ); - -void CEgon::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_EGON; - SET_MODEL(ENT(pev), "models/w_egon.mdl"); - - m_iDefaultAmmo = EGON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CEgon::Precache( void ) -{ - PRECACHE_MODEL("models/w_egon.mdl"); - PRECACHE_MODEL("models/v_egon.mdl"); - PRECACHE_MODEL("models/p_egon.mdl"); - - PRECACHE_MODEL("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND( EGON_SOUND_OFF ); - PRECACHE_SOUND( EGON_SOUND_RUN ); - PRECACHE_SOUND( EGON_SOUND_STARTUP ); - - PRECACHE_MODEL( EGON_BEAM_SPRITE ); - PRECACHE_MODEL( EGON_FLARE_SPRITE ); - - PRECACHE_SOUND ("weapons/357_cock1.wav"); - - m_usEgonFire = PRECACHE_EVENT ( 1, "events/egon_fire.sc" ); - m_usEgonStop = PRECACHE_EVENT ( 1, "events/egon_stop.sc" ); -} - - -BOOL CEgon::Deploy( void ) -{ - m_deployed = FALSE; - m_fireState = FIRE_OFF; - return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" ); -} - -int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - - - -void CEgon::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( EGON_HOLSTER ); - - EndAttack(); -} - -int CEgon::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 2; - p->iId = m_iId = WEAPON_EGON; - p->iFlags = 0; - p->iWeight = EGON_WEIGHT; - - return 1; -} - -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 - -float CEgon::GetPulseInterval( void ) -{ - return EGON_PULSE_INTERVAL; -} - -float CEgon::GetDischargeInterval( void ) -{ - return EGON_DISCHARGE_INTERVAL; -} - -BOOL CEgon::HasAmmo( void ) -{ - if ( m_pPlayer->ammo_uranium <= 0 ) - return FALSE; - - return TRUE; -} - -void CEgon::UseAmmo( int count ) -{ - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= count ) - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= count; - else - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = 0; -} - -void CEgon::Attack( void ) -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - - if ( m_fireState != FIRE_OFF || m_pBeam ) - { - EndAttack(); - } - else - { - PlayEmptySound( ); - } - return; - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - switch( m_fireState ) - { - case FIRE_OFF: - { - if ( !HasAmmo() ) - { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; - PlayEmptySound( ); - return; - } - - m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP. - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 ); - - m_shakeTime = 0; - - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - pev->fuser1 = UTIL_WeaponTimeBase() + 2; - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - m_fireState = FIRE_CHARGE; - } - break; - - case FIRE_CHARGE: - { - Fire( vecSrc, vecAiming ); - m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - - if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) - { - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); - pev->fuser1 = 1000; - } - - if ( !HasAmmo() ) - { - EndAttack(); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - } - - } - break; - } -} - -void CEgon::PrimaryAttack( void ) -{ - m_fireMode = FIRE_WIDE; - Attack(); - -} - -void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) -{ - Vector vecDest = vecOrigSrc + vecDir * 2048; - edict_t *pentIgnore; - TraceResult tr; - - pentIgnore = m_pPlayer->edict(); - Vector tmpSrc = vecOrigSrc + gpGlobals->v_up * -8 + gpGlobals->v_right * 3; - - // ALERT( at_console, "." ); - - UTIL_TraceLine( vecOrigSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr ); - - if (tr.fAllSolid) - return; - -#ifndef CLIENT_DLL - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - if ( m_pSprite && pEntity->pev->takedamage ) - { - m_pSprite->pev->effects &= ~EF_NODRAW; - } - else if ( m_pSprite ) - { - m_pSprite->pev->effects |= EF_NODRAW; - } - } - - -#endif - - float timedist = 0.0f; - - switch ( m_fireMode ) - { - case FIRE_NARROW: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // Narrow mode only does damage to the entity it hits - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonNarrow, vecDir, &tr, DMG_ENERGYBEAM ); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // multiplayer uses 1 ammo every 1/10th second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - else - { - // single player, use 3 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.166; - } - } - - pev->dmgtime = gpGlobals->time + GetPulseInterval(); - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetPulseInterval(); - break; - - case FIRE_WIDE: -#ifndef CLIENT_DLL - if ( pev->dmgtime < gpGlobals->time ) - { - // wide mode does damage to the ent, and radius damage - ClearMultiDamage(); - if (pEntity->pev->takedamage) - { - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgEgonWide, vecDir, &tr, DMG_ENERGYBEAM | DMG_ALWAYSGIB); - } - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - - if ( g_pGameRules->IsMultiplayer() ) - { - // radius damage a little more potent in multiplayer. - ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); - } - - if ( !m_pPlayer->IsAlive() ) - return; - - if ( g_pGameRules->IsMultiplayer() ) - { - //multiplayer uses 5 ammo/second - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.2; - } - } - else - { - // Wide mode uses 10 charges per second in single player - if ( gpGlobals->time >= m_flAmmoUseTime ) - { - UseAmmo( 1 ); - m_flAmmoUseTime = gpGlobals->time + 0.1; - } - } - - pev->dmgtime = gpGlobals->time + GetDischargeInterval(); - if ( m_shakeTime < gpGlobals->time ) - { - UTIL_ScreenShake( tr.vecEndPos, 5.0, 150.0, 0.75, 250.0 ); - m_shakeTime = gpGlobals->time + 1.5; - } - } -#endif - timedist = ( pev->dmgtime - gpGlobals->time ) / GetDischargeInterval(); - break; - } - - if ( timedist < 0 ) - timedist = 0; - else if ( timedist > 1 ) - timedist = 1; - timedist = 1-timedist; - - UpdateEffect( tmpSrc, tr.vecEndPos, timedist ); -} - - -void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, float timeBlend ) -{ -#ifndef CLIENT_DLL - if ( !m_pBeam ) - { - CreateEffect(); - } - - m_pBeam->SetStartPos( endPoint ); - m_pBeam->SetBrightness( static_cast(255 - (timeBlend*180)) ); - m_pBeam->SetWidth( static_cast(40 - (timeBlend*20)) ); - - if ( m_fireMode == FIRE_WIDE ) - m_pBeam->SetColor( static_cast(30 + (25*timeBlend)), static_cast(30 + (30*timeBlend)), static_cast(64 + 80*fabs(sin(gpGlobals->time*10))) ); - else - m_pBeam->SetColor( static_cast(60 + (25*timeBlend)), static_cast(120 + (30*timeBlend)), static_cast(64 + 80*fabs(sin(gpGlobals->time*10))) ); - - - UTIL_SetOrigin( m_pSprite->pev, endPoint ); - m_pSprite->pev->frame += 8 * gpGlobals->frametime; - if ( m_pSprite->pev->frame > m_pSprite->Frames() ) - m_pSprite->pev->frame = 0; - - m_pNoise->SetStartPos( endPoint ); - -#endif - -} - -void CEgon::CreateEffect( void ) -{ - -#ifndef CLIENT_DLL - DestroyEffect(); - - m_pBeam = CBeam::BeamCreate( EGON_BEAM_SPRITE, 40 ); - m_pBeam->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pBeam->SetFlags( BEAM_FSINE ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition - m_pBeam->pev->flags |= FL_SKIPLOCALHOST; - m_pBeam->pev->owner = m_pPlayer->edict(); - - m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 ); - m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() ); - m_pNoise->SetScrollRate( 25 ); - m_pNoise->SetBrightness( 100 ); - m_pNoise->SetEndAttachment( 1 ); - m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY; - m_pNoise->pev->flags |= FL_SKIPLOCALHOST; - m_pNoise->pev->owner = m_pPlayer->edict(); - - m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE ); - m_pSprite->pev->scale = 1.0; - m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY; - m_pSprite->pev->flags |= FL_SKIPLOCALHOST; - m_pSprite->pev->owner = m_pPlayer->edict(); - - if ( m_fireMode == FIRE_WIDE ) - { - m_pBeam->SetScrollRate( 50 ); - m_pBeam->SetNoise( 20 ); - m_pNoise->SetColor( 50, 50, 255 ); - m_pNoise->SetNoise( 8 ); - } - else - { - m_pBeam->SetScrollRate( 110 ); - m_pBeam->SetNoise( 5 ); - m_pNoise->SetColor( 80, 120, 255 ); - m_pNoise->SetNoise( 2 ); - } -#endif - -} - - -void CEgon::DestroyEffect( void ) -{ - -#ifndef CLIENT_DLL - if ( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } - if ( m_pNoise ) - { - UTIL_Remove( m_pNoise ); - m_pNoise = NULL; - } - if ( m_pSprite ) - { - if ( m_fireMode == FIRE_WIDE ) - m_pSprite->Expand( 10, 500 ); - else - UTIL_Remove( m_pSprite ); - m_pSprite = NULL; - } -#endif - -} - - - -void CEgon::WeaponIdle( void ) -{ - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > gpGlobals->time ) - return; - - if ( m_fireState != FIRE_OFF ) - EndAttack(); - - int iAnim; - - float flRand = RANDOM_FLOAT(0,1); - - if ( flRand <= 0.5 ) - { - iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - SendWeaponAnim( iAnim ); - m_deployed = TRUE; -} - - - -void CEgon::EndAttack( void ) -{ - bool bMakeNoise = false; - - if ( m_fireState != FIRE_OFF ) //Checking the button just in case!. - bMakeNoise = true; - - PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - - m_fireState = FIRE_OFF; - - DestroyEffect(); -} - - - -class CEgonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_chainammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_egonclip, CEgonAmmo ); - -#endif diff --git a/sdk/dlls/enginecallback.h b/sdk/dlls/enginecallback.h deleted file mode 100644 index d74ec5b..0000000 --- a/sdk/dlls/enginecallback.h +++ /dev/null @@ -1,165 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ENGINECALLBACK_H -#define ENGINECALLBACK_H -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#include "event_flags.h" - -// Fix warning in MSVC8 -#undef SERVER_EXECUTE - -// Must be provided by user of this code -extern enginefuncs_t g_engfuncs; - -// The actual engine callbacks -#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) -#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) -#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) -#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) -#define SET_MODEL (*g_engfuncs.pfnSetModel) -#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) -#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) -#define SET_SIZE (*g_engfuncs.pfnSetSize) -#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) -#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) -#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) -#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) -#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) -#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) -#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) -#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) -#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) -#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) -#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) -#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) -#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) -#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor) -#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) -#define WALK_MOVE (*g_engfuncs.pfnWalkMove) -#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) -#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) -#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) -#define TRACE_LINE (*g_engfuncs.pfnTraceLine) -#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) -#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) -#define TRACE_HULL (*g_engfuncs.pfnTraceHull) -#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) -#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) -#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) -#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) -#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) -#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) -#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) -#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) -#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init) -#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer) -#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte) -#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) -#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) -#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) -#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) - -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) { - (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); -} -#define MESSAGE_END (*g_engfuncs.pfnMessageEnd) -#define WRITE_BYTE (*g_engfuncs.pfnWriteByte) -#define WRITE_CHAR (*g_engfuncs.pfnWriteChar) -#define WRITE_SHORT (*g_engfuncs.pfnWriteShort) -#define WRITE_LONG (*g_engfuncs.pfnWriteLong) -#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle) -#define WRITE_COORD (*g_engfuncs.pfnWriteCoord) -#define WRITE_STRING (*g_engfuncs.pfnWriteString) -#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) -#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) -#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) -#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) -#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) -#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) -#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) -#define ALERT (*g_engfuncs.pfnAlertMessage) -#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) -#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) -inline void *GET_PRIVATE( edict_t *pent ) -{ - if ( pent ) - return pent->pvPrivateData; - return NULL; -} - -#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) -//#define STRING (*g_engfuncs.pfnSzFromIndex) -#define ALLOC_STRING (*g_engfuncs.pfnAllocString) -#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) -#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) -#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) -#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) -#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) -#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) -#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) -#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) -#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) -#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) -#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) -#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) -#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) -#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) -#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) -#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) -#define SET_VIEW (*g_engfuncs.pfnSetView) -#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) -#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe) -#define FREE_FILE (*g_engfuncs.pfnFreeFile) -#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) -#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) -#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) -#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) -#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) - -#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) -#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) - -#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) -#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) - -#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) - -#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) -#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) -#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder ) -#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer ) - -#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer ) - -#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField ) -#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex ) -#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex ) - -#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString ) - -#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask ) - -#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline ) - -#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified ) - -#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) - -#endif //ENGINECALLBACK_H diff --git a/sdk/dlls/explode.cpp b/sdk/dlls/explode.cpp deleted file mode 100644 index 4e5f1c1..0000000 --- a/sdk/dlls/explode.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== explode.cpp ======================================================== - - Explosion-related code - -*/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "decals.h" -#include "explode.h" - -// Spark Shower -class CShower : public CBaseEntity -{ - void Spawn( void ); - void Think( void ); - void Touch( CBaseEntity *pOther ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -LINK_ENTITY_TO_CLASS( spark_shower, CShower ); - -void CShower::Spawn( void ) -{ - pev->velocity = RANDOM_FLOAT( 200, 300 ) * pev->angles; - pev->velocity.x += RANDOM_FLOAT(-100.f,100.f); - pev->velocity.y += RANDOM_FLOAT(-100.f,100.f); - if ( pev->velocity.z >= 0 ) - pev->velocity.z += 200; - else - pev->velocity.z -= 200; - pev->movetype = MOVETYPE_BOUNCE; - pev->gravity = 0.5; - pev->nextthink = gpGlobals->time + 0.1; - pev->solid = SOLID_NOT; - SET_MODEL( edict(), "models/grenade.mdl"); // Need a model, just use the grenade, we don't draw it anyway - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->speed = RANDOM_FLOAT( 0.5, 1.5 ); - - pev->angles = g_vecZero; -} - - -void CShower::Think( void ) -{ - UTIL_Sparks( pev->origin ); - - pev->speed -= 0.1; - if ( pev->speed > 0 ) - pev->nextthink = gpGlobals->time + 0.1; - else - UTIL_Remove( this ); - pev->flags &= ~FL_ONGROUND; -} - -void CShower::Touch( CBaseEntity *pOther ) -{ - if ( pev->flags & FL_ONGROUND ) - pev->velocity = pev->velocity * 0.1; - else - pev->velocity = pev->velocity * 0.6; - - if ( (pev->velocity.x*pev->velocity.x+pev->velocity.y*pev->velocity.y) < 10.0 ) - pev->speed = 0; -} - -class CEnvExplosion : public CBaseMonster -{ -public: - void Spawn( ); - void EXPORT Smoke ( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_iMagnitude;// how large is the fireball? how much damage? - int m_spriteScale; // what's the exact fireball sprite scale? -}; - -TYPEDESCRIPTION CEnvExplosion::m_SaveData[] = -{ - DEFINE_FIELD( CEnvExplosion, m_iMagnitude, FIELD_INTEGER ), - DEFINE_FIELD( CEnvExplosion, m_spriteScale, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CEnvExplosion, CBaseMonster ); -LINK_ENTITY_TO_CLASS( env_explosion, CEnvExplosion ); - -void CEnvExplosion::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - m_iMagnitude = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CEnvExplosion::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - - pev->movetype = MOVETYPE_NONE; - /* - if ( m_iMagnitude > 250 ) - { - m_iMagnitude = 250; - } - */ - - float flSpriteScale; - flSpriteScale = ( m_iMagnitude - 50) * 0.6; - - /* - if ( flSpriteScale > 50 ) - { - flSpriteScale = 50; - } - */ - if ( flSpriteScale < 10 ) - { - flSpriteScale = 10; - } - - m_spriteScale = (int)flSpriteScale; -} - -void CEnvExplosion::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TraceResult tr; - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - - Vector vecSpot;// trace starts here! - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); - - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); - - // Pull out of the wall a bit - if ( tr.flFraction != 1.0 ) - { - pev->origin = tr.vecEndPos + (tr.vecPlaneNormal * (m_iMagnitude - 24) * 0.6); - } - else - { - pev->origin = pev->origin; - } - - // draw decal - if (! ( pev->spawnflags & SF_ENVEXPLOSION_NODECAL)) - { - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( &tr, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( &tr, DECAL_SCORCH2 ); - } - } - - // draw fireball - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOFIREBALL ) ) - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - } - else - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( 0 ); // no sprite - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - } - - // do damage - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NODAMAGE ) ) - { - RadiusDamage ( pev, pev, m_iMagnitude, CLASS_NONE, DMG_BLAST ); - } - - SetThink( &CEnvExplosion::Smoke ); - pev->nextthink = gpGlobals->time + 0.3; - - // draw sparks - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSPARKS ) ) - { - int sparkCount = RANDOM_LONG(0,3); - - for ( int i = 0; i < sparkCount; i++ ) - { - Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL ); - } - } -} - -void CEnvExplosion::Smoke( void ) -{ - if ( !( pev->spawnflags & SF_ENVEXPLOSION_NOSMOKE ) ) - { - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( (BYTE)m_spriteScale ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - - if ( !(pev->spawnflags & SF_ENVEXPLOSION_REPEATABLE) ) - { - UTIL_Remove( this ); - } -} - - -// HACKHACK -- create one of these and fake a keyvalue to get the right explosion setup -void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ) -{ - KeyValueData kvd; - char buf[128]; - - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, angles, pOwner ); - sprintf( buf, "%3d", magnitude ); - kvd.szKeyName = "iMagnitude"; - kvd.szValue = buf; - pExplosion->KeyValue( &kvd ); - if ( !doDamage ) - pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; - - pExplosion->Spawn(); - pExplosion->Use( NULL, NULL, USE_TOGGLE, 0 ); -} diff --git a/sdk/dlls/explode.h b/sdk/dlls/explode.h deleted file mode 100644 index 3feb011..0000000 --- a/sdk/dlls/explode.h +++ /dev/null @@ -1,32 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EXPLODE_H -#define EXPLODE_H - - -#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage -#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired? -#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball -#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke -#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark -#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark - -extern DLL_GLOBAL short g_sModelIndexFireball; -extern DLL_GLOBAL short g_sModelIndexSmoke; - - -extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ); - -#endif //EXPLODE_H diff --git a/sdk/dlls/extdll.h b/sdk/dlls/extdll.h deleted file mode 100644 index 655684a..0000000 --- a/sdk/dlls/extdll.h +++ /dev/null @@ -1,111 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef EXTDLL_H -#define EXTDLL_H - - -// -// Global header file for extension DLLs -// - -// Allow "DEBUG" in addition to default "_DEBUG" -#ifdef _DEBUG -#define DEBUG 1 -#endif - -// Silence certain warnings -#ifdef _MSC_VER - #pragma warning(disable : 4244) // int or float down-conversion - #pragma warning(disable : 4305) // int or float data truncation - #pragma warning(disable : 4201) // nameless struct/union - #pragma warning(disable : 4514) // unreferenced inline function removed - #pragma warning(disable : 4100) // unreferenced formal parameter - - #if _MSC_VER >= 1400 - #ifndef _CRT_SECURE_NO_DEPRECATE - #define _CRT_SECURE_NO_DEPRECATE - #endif - - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - - #pragma warning(disable: 4996) // deprecated functions - #endif -#endif - -#include "archtypes.h" // DAL - -// Prevent tons of unused windows definitions -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOWINRES -#define NOSERVICE -#define NOMCX -#define NOIME -#include "windows.h" -#else // _WIN32 -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE (!FALSE) -#endif -typedef uint32 ULONG; -typedef unsigned char BYTE; -typedef int BOOL; -#define MAX_PATH PATH_MAX -#include -#include -#include // memset -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#ifndef _vsnprintf -#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) -#endif -#endif //_WIN32 - -// Misc C-runtime library headers -#include "stdio.h" -#include "stdlib.h" -#include "math.h" - -// Header file containing definition of globalvars_t and entvars_t -typedef unsigned int func_t; // -typedef unsigned int string_t; // from engine's pr_comp.h; -typedef float vec_t; // needed before including progdefs.h - -// Vector class -#include "vector.h" - -// Defining it as a (bogus) struct helps enforce type-checking -#define vec3_t Vector - -// Shared engine/DLL constants -#include "const.h" -#include "progdefs.h" -#include "edict.h" - -// Shared header describing protocol between engine and DLLs -#include "eiface.h" - -// Shared header between the client DLL and the game DLLs -#include "cdll_dll.h" - -#endif //EXTDLL_H diff --git a/sdk/dlls/flyingmonster.cpp b/sdk/dlls/flyingmonster.cpp deleted file mode 100644 index 4fae59e..0000000 --- a/sdk/dlls/flyingmonster.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" - -#define FLYING_AE_FLAP (8) -#define FLYING_AE_FLAPSOUND (9) - - -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; - -int CFlyingMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - // UNDONE: need to check more than the endpoint - if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER)) - { - // ALERT(at_aiconsole, "can't swim out of water\n"); - return FALSE; - } - - TraceResult tr; - - UTIL_TraceHull( vecStart + Vector( 0, 0, 32 ), vecEnd + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, edict(), &tr ); - - // ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z ); - // ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z ); - - if (pflDist) - { - *pflDist = ( (tr.vecEndPos - Vector( 0, 0, 32 )) - vecStart ).Length();// get the distance. - } - - // ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - return LOCALMOVE_VALID; - return LOCALMOVE_INVALID; - } - - return LOCALMOVE_VALID; -} - - -BOOL CFlyingMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) -{ - return CBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex ); -} - - -Activity CFlyingMonster :: GetStoppedActivity( void ) -{ - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - - return ACT_HOVER; -} - - -void CFlyingMonster :: Stop( void ) -{ - Activity stopped = GetStoppedActivity(); - if ( m_IdealActivity != stopped ) - { - m_flightSpeed = 0; - m_IdealActivity = stopped; - } - pev->angles.z = 0; - pev->angles.x = 0; - m_vecTravel = g_vecZero; -} - - -float CFlyingMonster :: ChangeYaw( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if ( m_IdealActivity != GetStoppedActivity() ) - { - if ( diff < -20 ) - target = 90; - else if ( diff > 20 ) - target = -90; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * gpGlobals->frametime ); - } - return CBaseMonster::ChangeYaw( speed ); -} - - -void CFlyingMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_STEP; - ClearBits( pev->flags, FL_ONGROUND ); - pev->angles.z = 0; - pev->angles.x = 0; - CBaseMonster::Killed( pevAttacker, iGib ); -} - - -void CFlyingMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case FLYING_AE_FLAP: - m_flightSpeed = 400; - break; - - case FLYING_AE_FLAPSOUND: - if ( m_pFlapSound ) - EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM ); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - - -void CFlyingMonster :: Move( float flInterval ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - m_flGroundSpeed = m_flightSpeed; - CBaseMonster::Move( flInterval ); -} - - -BOOL CFlyingMonster:: ShouldAdvanceRoute( float flWaypointDist ) -{ - // Get true 3D distance to the goal so we actually reach the correct height - if ( m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL ) - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length(); - - if ( flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime) ) - return TRUE; - - return FALSE; -} - - -void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - if ( gpGlobals->time - m_stopTime > 1.0 ) - { - if ( m_IdealActivity != m_movementActivity ) - { - m_IdealActivity = m_movementActivity; - m_flGroundSpeed = m_flightSpeed = 200; - } - } - Vector vecMove = pev->origin + (( vecDir + (m_vecTravel * m_momentum) ).Normalize() * (m_flGroundSpeed * flInterval)); - - if ( m_IdealActivity != m_movementActivity ) - { - m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75 * gpGlobals->frametime ); - if ( m_flightSpeed < 100 ) - m_stopTime = gpGlobals->time; - } - else - m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300 * gpGlobals->frametime ); - - if ( CheckLocalMove ( pev->origin, vecMove, pTargetEnt, NULL ) ) - { - m_vecTravel = (vecMove - pev->origin); - m_vecTravel = m_vecTravel.Normalize(); - UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE); - } - else - { - m_IdealActivity = GetStoppedActivity(); - m_stopTime = gpGlobals->time; - m_vecTravel = g_vecZero; - } - } - else - CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval ); -} - - -float CFlyingMonster::CeilingZ( const Vector &position ) -{ - TraceResult tr; - - Vector minUp = position; - Vector maxUp = position; - maxUp.z += 4096.0; - - UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr); - if (tr.flFraction != 1.0) - maxUp.z = tr.vecEndPos.z; - - if ((pev->flags) & FL_SWIM) - { - return UTIL_WaterLevel( position, minUp.z, maxUp.z ); - } - return maxUp.z; -} - -BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction) -{ - int conPosition = UTIL_PointContents(position); - if ( (((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER)) - { - // SWIMING & !WATER - // or FLYING & WATER - // - *pFraction = 0.0; - return TRUE; // We hit a water boundary because we are where we don't belong. - } - int conProbe = UTIL_PointContents(probe); - if (conProbe == conPosition) - { - // The probe is either entirely inside the water (for fish) or entirely - // outside the water (for birds). - // - *pFraction = 1.0; - return FALSE; - } - - Vector ProbeUnit = (probe-position).Normalize(); - float ProbeLength = (probe-position).Length(); - float maxProbeLength = ProbeLength; - float minProbeLength = 0; - - float diff = maxProbeLength - minProbeLength; - while (diff > 1.0) - { - float midProbeLength = minProbeLength + diff/2.0; - Vector midProbeVec = midProbeLength * ProbeUnit; - if (UTIL_PointContents(position+midProbeVec) == conPosition) - { - minProbeLength = midProbeLength; - } - else - { - maxProbeLength = midProbeLength; - } - diff = maxProbeLength - minProbeLength; - } - *pFraction = minProbeLength/ProbeLength; - - return TRUE; -} - -float CFlyingMonster::FloorZ( const Vector &position ) -{ - TraceResult tr; - - Vector down = position; - down.z -= 2048; - - UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr ); - - if ( tr.flFraction != 1.0 ) - return tr.vecEndPos.z; - - return down.z; -} - diff --git a/sdk/dlls/flyingmonster.h b/sdk/dlls/flyingmonster.h deleted file mode 100644 index 85ef61a..0000000 --- a/sdk/dlls/flyingmonster.h +++ /dev/null @@ -1,53 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -// Base class for flying monsters. This overrides the movement test & execution code from CBaseMonster - -#ifndef FLYINGMONSTER_H -#define FLYINGMONSTER_H - -class CFlyingMonster : public CBaseMonster -{ -public: - int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space - BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); - Activity GetStoppedActivity( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - void Stop( void ); - float ChangeYaw( int speed ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void Move( float flInterval = 0.1 ); - BOOL ShouldAdvanceRoute( float flWaypointDist ); - - inline void SetFlyingMomentum( float momentum ) { m_momentum = momentum; } - inline void SetFlyingFlapSound( const char *pFlapSound ) { m_pFlapSound = pFlapSound; } - inline void SetFlyingSpeed( float speed ) { m_flightSpeed = speed; } - float CeilingZ( const Vector &position ); - float FloorZ( const Vector &position ); - BOOL ProbeZ( const Vector &position, const Vector &probe, float *pFraction ); - - - // UNDONE: Save/restore this stuff!!! -protected: - Vector m_vecTravel; // Current direction - float m_flightSpeed; // Current flight speed (decays when not flapping or gliding) - float m_stopTime; // Last time we stopped (to avoid switching states too soon) - float m_momentum; // Weight for desired vs. momentum velocity - const char *m_pFlapSound; -}; - - -#endif //FLYINGMONSTER_H - diff --git a/sdk/dlls/func_break.cpp b/sdk/dlls/func_break.cpp deleted file mode 100644 index 02334d1..0000000 --- a/sdk/dlls/func_break.cpp +++ /dev/null @@ -1,1010 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== bmodels.cpp ======================================================== - - spawn, think, and use functions for entities that use brush models - -*/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "func_break.h" -#include "decals.h" -#include "explode.h" - -extern DLL_GLOBAL Vector g_vecAttackDir; - -// =================== FUNC_Breakable ============================================== - -// Just add more items to the bottom of this array and they will automagically be supported -// This is done instead of just a classname in the FGD so we can control which entities can -// be spawned, and still remain fairly flexible -const char *CBreakable::pSpawnObjects[] = -{ - NULL, // 0 - "item_battery", // 1 - "item_healthkit", // 2 - "weapon_9mmhandgun",// 3 - "ammo_9mmclip", // 4 - "weapon_9mmAR", // 5 - "ammo_9mmAR", // 6 - "ammo_ARgrenades", // 7 - "weapon_shotgun", // 8 - "ammo_buckshot", // 9 - "weapon_crossbow", // 10 - "ammo_crossbow", // 11 - "weapon_357", // 12 - "ammo_357", // 13 - "weapon_rpg", // 14 - "ammo_rpgclip", // 15 - "ammo_gaussclip", // 16 - "weapon_handgrenade",// 17 - "weapon_tripmine", // 18 - "weapon_satchel", // 19 - "weapon_snark", // 20 - "weapon_hornetgun", // 21 -}; - -void CBreakable::KeyValue( KeyValueData* pkvd ) -{ - // UNDONE_WC: explicitly ignoring these fields, but they shouldn't be in the map file! - if (FStrEq(pkvd->szKeyName, "explosion")) - { - if (!stricmp(pkvd->szValue, "directed")) - m_Explosion = expDirected; - else if (!stricmp(pkvd->szValue, "random")) - m_Explosion = expRandom; - else - m_Explosion = expRandom; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "material")) - { - int i = atoi( pkvd->szValue); - - // 0:glass, 1:metal, 2:flesh, 3:wood - - if ((i < 0) || (i >= matLastMaterial)) - m_Material = matWood; - else - m_Material = (Materials)i; - - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deadmodel")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "shards")) - { -// m_iShards = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "gibmodel") ) - { - m_iszGibModel = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spawnobject") ) - { - int object = atoi( pkvd->szValue ); - if ( object > 0 && object < static_cast(ARRAYSIZE(pSpawnObjects)) ) - m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "explodemagnitude") ) - { - ExplosionSetMagnitude( atoi( pkvd->szValue ) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "lip") ) - pkvd->fHandled = TRUE; - else - CBaseDelay::KeyValue( pkvd ); -} - - -// -// func_breakable - bmodel that breaks into pieces after taking damage -// -LINK_ENTITY_TO_CLASS( func_breakable, CBreakable ); -TYPEDESCRIPTION CBreakable::m_SaveData[] = -{ - DEFINE_FIELD( CBreakable, m_Material, FIELD_INTEGER ), - DEFINE_FIELD( CBreakable, m_Explosion, FIELD_INTEGER ), - -// Don't need to save/restore these because we precache after restore -// DEFINE_FIELD( CBreakable, m_idShard, FIELD_INTEGER ), - - DEFINE_FIELD( CBreakable, m_angle, FIELD_FLOAT ), - DEFINE_FIELD( CBreakable, m_iszGibModel, FIELD_STRING ), - DEFINE_FIELD( CBreakable, m_iszSpawnObject, FIELD_STRING ), - - // Explosion magnitude is stored in pev->impulse -}; - -IMPLEMENT_SAVERESTORE( CBreakable, CBaseEntity ); - -void CBreakable::Spawn( void ) -{ - Precache( ); - - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) - pev->takedamage = DAMAGE_NO; - else - pev->takedamage = DAMAGE_YES; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - m_angle = pev->angles.y; - pev->angles.y = 0; - - // HACK: matGlass can receive decals, we need the client to know about this - // so use class to store the material flag - if ( m_Material == matGlass ) - { - pev->playerclass = 1; - } - - SET_MODEL(ENT(pev), STRING(pev->model) );//set size and link into world. - - SetTouch( &CBreakable::BreakTouch ); - if ( FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) ) // Only break on trigger - SetTouch( NULL ); - - // Flag unbreakable glass as "worldbrush" so it will block ALL tracelines - if ( !IsBreakable() && pev->rendermode != kRenderNormal ) - pev->flags |= FL_WORLDBRUSH; -} - - -const char *CBreakable::pSoundsWood[] = -{ - "debris/wood1.wav", - "debris/wood2.wav", - "debris/wood3.wav", -}; - -const char *CBreakable::pSoundsFlesh[] = -{ - "debris/flesh1.wav", - "debris/flesh2.wav", - "debris/flesh3.wav", - "debris/flesh5.wav", - "debris/flesh6.wav", - "debris/flesh7.wav", -}; - -const char *CBreakable::pSoundsMetal[] = -{ - "debris/metal1.wav", - "debris/metal2.wav", - "debris/metal3.wav", -}; - -const char *CBreakable::pSoundsConcrete[] = -{ - "debris/concrete1.wav", - "debris/concrete2.wav", - "debris/concrete3.wav", -}; - - -const char *CBreakable::pSoundsGlass[] = -{ - "debris/glass1.wav", - "debris/glass2.wav", - "debris/glass3.wav", -}; - -const char **CBreakable::MaterialSoundList( Materials precacheMaterial, int &soundCount ) -{ - const char **pSoundList = NULL; - - switch ( precacheMaterial ) - { - case matWood: - pSoundList = pSoundsWood; - soundCount = ARRAYSIZE(pSoundsWood); - break; - case matFlesh: - pSoundList = pSoundsFlesh; - soundCount = ARRAYSIZE(pSoundsFlesh); - break; - case matComputer: - case matUnbreakableGlass: - case matGlass: - pSoundList = pSoundsGlass; - soundCount = ARRAYSIZE(pSoundsGlass); - break; - - case matMetal: - pSoundList = pSoundsMetal; - soundCount = ARRAYSIZE(pSoundsMetal); - break; - - case matCinderBlock: - case matRocks: - pSoundList = pSoundsConcrete; - soundCount = ARRAYSIZE(pSoundsConcrete); - break; - - - case matCeilingTile: - case matNone: - default: - soundCount = 0; - break; - } - - return pSoundList; -} - -void CBreakable::MaterialSoundPrecache( Materials precacheMaterial ) -{ - const char **pSoundList; - int i, soundCount = 0; - - pSoundList = MaterialSoundList( precacheMaterial, soundCount ); - - for ( i = 0; i < soundCount; i++ ) - { - PRECACHE_SOUND( (char *)pSoundList[i] ); - } -} - -void CBreakable::MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ) -{ - const char **pSoundList; - int soundCount = 0; - - pSoundList = MaterialSoundList( soundMaterial, soundCount ); - - if ( soundCount ) - EMIT_SOUND( pEdict, CHAN_BODY, pSoundList[ RANDOM_LONG(0,soundCount-1) ], volume, 1.0 ); -} - - -void CBreakable::Precache( void ) -{ - const char *pGibName = NULL; - - switch (m_Material) - { - case matWood: - pGibName = "models/woodgibs.mdl"; - - PRECACHE_SOUND("debris/bustcrate1.wav"); - PRECACHE_SOUND("debris/bustcrate2.wav"); - break; - case matFlesh: - pGibName = "models/fleshgibs.mdl"; - - PRECACHE_SOUND("debris/bustflesh1.wav"); - PRECACHE_SOUND("debris/bustflesh2.wav"); - break; - case matComputer: - PRECACHE_SOUND("buttons/spark5.wav"); - PRECACHE_SOUND("buttons/spark6.wav"); - pGibName = "models/computergibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - - case matUnbreakableGlass: - case matGlass: - pGibName = "models/glassgibs.mdl"; - - PRECACHE_SOUND("debris/bustglass1.wav"); - PRECACHE_SOUND("debris/bustglass2.wav"); - break; - case matMetal: - pGibName = "models/metalplategibs.mdl"; - - PRECACHE_SOUND("debris/bustmetal1.wav"); - PRECACHE_SOUND("debris/bustmetal2.wav"); - break; - case matCinderBlock: - pGibName = "models/cindergibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matRocks: - pGibName = "models/rockgibs.mdl"; - - PRECACHE_SOUND("debris/bustconcrete1.wav"); - PRECACHE_SOUND("debris/bustconcrete2.wav"); - break; - case matCeilingTile: - pGibName = "models/ceilinggibs.mdl"; - - PRECACHE_SOUND ("debris/bustceiling.wav"); - break; - default: - break; - } - MaterialSoundPrecache( m_Material ); - if ( m_iszGibModel ) - pGibName = STRING(m_iszGibModel); - - m_idShard = PRECACHE_MODEL( (char *)pGibName ); - - // Precache the spawn item's data - if ( m_iszSpawnObject ) - UTIL_PrecacheOther( (char *)STRING( m_iszSpawnObject ) ); -} - -// play shard sound when func_breakable takes damage. -// the more damage, the louder the shard sound. - - -void CBreakable::DamageSound( void ) -{ - int pitch; - float fvol; - const char *rgpsz[6]; - int i = 0; - int material = m_Material; - -// if (RANDOM_LONG(0,1)) -// return; - - if (RANDOM_LONG(0,2)) - pitch = PITCH_NORM; - else - pitch = 95 + RANDOM_LONG(0,34); - - fvol = RANDOM_FLOAT(0.75, 1.0); - - if (material == matComputer && RANDOM_LONG(0,1)) - material = matMetal; - - switch (material) - { - case matComputer: - case matGlass: - case matUnbreakableGlass: - rgpsz[0] = "debris/glass1.wav"; - rgpsz[1] = "debris/glass2.wav"; - rgpsz[2] = "debris/glass3.wav"; - i = 3; - break; - - case matWood: - rgpsz[0] = "debris/wood1.wav"; - rgpsz[1] = "debris/wood2.wav"; - rgpsz[2] = "debris/wood3.wav"; - i = 3; - break; - - case matMetal: - rgpsz[0] = "debris/metal1.wav"; - rgpsz[1] = "debris/metal3.wav"; - rgpsz[2] = "debris/metal2.wav"; - i = 2; - break; - - case matFlesh: - rgpsz[0] = "debris/flesh1.wav"; - rgpsz[1] = "debris/flesh2.wav"; - rgpsz[2] = "debris/flesh3.wav"; - rgpsz[3] = "debris/flesh5.wav"; - rgpsz[4] = "debris/flesh6.wav"; - rgpsz[5] = "debris/flesh7.wav"; - i = 6; - break; - - case matRocks: - case matCinderBlock: - rgpsz[0] = "debris/concrete1.wav"; - rgpsz[1] = "debris/concrete2.wav"; - rgpsz[2] = "debris/concrete3.wav"; - i = 3; - break; - - case matCeilingTile: - // UNDONE: no ceiling tile shard sound yet - i = 0; - break; - } - - if (i) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, rgpsz[RANDOM_LONG(0,i-1)], fvol, ATTN_NORM, 0, pitch); -} - -void CBreakable::BreakTouch( CBaseEntity *pOther ) -{ - float flDamage; - entvars_t* pevToucher = pOther->pev; - - // only players can break these right now - if ( !pOther->IsPlayer() || !IsBreakable() ) - { - return; - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_TOUCH ) ) - {// can be broken when run into - flDamage = pevToucher->velocity.Length() * 0.01; - - if (flDamage >= pev->health) - { - SetTouch( NULL ); - TakeDamage(pevToucher, pevToucher, flDamage, DMG_CRUSH); - - // do a little damage to player if we broke glass or computer - pOther->TakeDamage( pev, pev, flDamage/4, DMG_SLASH ); - } - } - - if ( FBitSet ( pev->spawnflags, SF_BREAK_PRESSURE ) && pevToucher->absmin.z >= pev->maxs.z - 2 ) - {// can be broken when stood upon - - // play creaking sound here. - DamageSound(); - - SetThink ( &CBreakable::Die ); - SetTouch( NULL ); - - if ( m_flDelay == 0 ) - {// !!!BUGBUG - why doesn't zero delay work? - m_flDelay = 0.1; - } - - pev->nextthink = pev->ltime + m_flDelay; - - } - -} - - -// -// Smash the our breakable object -// - -// Break when triggered -void CBreakable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsBreakable() ) - { - pev->angles.y = m_angle; - UTIL_MakeVectors(pev->angles); - g_vecAttackDir = gpGlobals->v_forward; - - Die(); - } -} - - -void CBreakable::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - // random spark if this is a 'computer' object - if (RANDOM_LONG(0,1) ) - { - switch( m_Material ) - { - case matComputer: - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - break; - - case matUnbreakableGlass: - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - break; - - default: - break; - } - } - - CBaseDelay::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - -//========================================================= -// Special takedamage for func_breakable. Allows us to make -// exceptions that are breakable-specific -// bitsDamageType indicates the type of damage sustained ie: DMG_CRUSH -//========================================================= -int CBreakable :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - Vector vecTemp; - - // if Attacker == Inflictor, the attack was a melee or other instant-hit attack. - // (that is, no actual entity projectile was involved in the attack so use the shooter's origin). - if ( pevAttacker == pevInflictor ) - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - - // if a client hit the breakable with a crowbar, and breakable is crowbar-sensitive, break it now. - if ( FBitSet ( pevAttacker->flags, FL_CLIENT ) && - FBitSet ( pev->spawnflags, SF_BREAK_CROWBAR ) && (bitsDamageType & DMG_CLUB)) - flDamage = pev->health; - } - else - // an actual missile was involved. - { - vecTemp = pevInflictor->origin - ( pev->absmin + ( pev->size * 0.5 ) ); - } - - if (!IsBreakable()) - return 0; - - // Breakables take double damage from the crowbar - if ( bitsDamageType & DMG_CLUB ) - flDamage *= 2; - - // Boxes / glass / etc. don't take much poison damage, just the impact of the dart - consider that 10% - if ( bitsDamageType & DMG_POISON ) - flDamage *= 0.1; - -// this global is still used for glass and other non-monster killables, along with decals. - g_vecAttackDir = vecTemp.Normalize(); - -// do the damage - pev->health -= flDamage; - if (pev->health <= 0) - { - Killed( pevAttacker, GIB_NORMAL ); - Die(); - return 0; - } - - // Make a shard noise each time func breakable is hit. - // Don't play shard noise if cbreakable actually died. - - DamageSound(); - - return 1; -} - - -void CBreakable::Die( void ) -{ - Vector vecSpot;// shard origin - Vector vecVelocity;// shard velocity - char cFlag = 0; - int pitch; - float fvol; - - pitch = 95 + RANDOM_LONG(0,29); - - if (pitch > 97 && pitch < 103) - pitch = 100; - - // The more negative pev->health, the louder - // the sound should be. - - fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(static_cast(pev->health)) / 100.0); - - if (fvol > 1.0) - fvol = 1.0; - - - switch (m_Material) - { - case matGlass: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_GLASS; - break; - - case matWood: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_WOOD; - break; - - case matComputer: - case matMetal: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_METAL; - break; - - case matFlesh: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_FLESH; - break; - - case matRocks: - case matCinderBlock: - switch ( RANDOM_LONG(0,1) ) - { - case 0: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch); - break; - case 1: EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch); - break; - } - cFlag = BREAK_CONCRETE; - break; - - case matCeilingTile: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch); - break; - - default: - break; - } - - - if (m_Explosion == expDirected) - vecVelocity = g_vecAttackDir * 200; - else - { - vecVelocity.x = 0; - vecVelocity.y = 0; - vecVelocity.z = 0; - } - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( pev->size.x); - WRITE_COORD( pev->size.y); - WRITE_COORD( pev->size.z); - - // velocity - WRITE_COORD( vecVelocity.x ); - WRITE_COORD( vecVelocity.y ); - WRITE_COORD( vecVelocity.z ); - - // randomization - WRITE_BYTE( 10 ); - - // Model - WRITE_SHORT( m_idShard ); //model id# - - // # of shards - WRITE_BYTE( 0 ); // let client decide - - // duration - WRITE_BYTE( 25 );// 2.5 seconds - - // flags - WRITE_BYTE( cFlag ); - MESSAGE_END(); - - float size = pev->size.x; - if ( size < pev->size.y ) - size = pev->size.y; - if ( size < pev->size.z ) - size = pev->size.z; - - // !!! HACK This should work! - // Build a box above the entity that looks like an 8 pixel high sheet - Vector mins = pev->absmin; - Vector maxs = pev->absmax; - mins.z = pev->absmax.z; - maxs.z += 8; - - // BUGBUG -- can only find 256 entities on a breakable -- should be enough - CBaseEntity *pList[256]; - int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND ); - if ( count ) - { - for ( int i = 0; i < count; i++ ) - { - ClearBits( pList[i]->pev->flags, FL_ONGROUND ); - pList[i]->pev->groundentity = NULL; - } - } - - // Don't fire something that could fire myself - pev->targetname = 0; - - pev->solid = SOLID_NOT; - // Fire targets on break - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - - SetThink( &CBreakable::SUB_Remove ); - pev->nextthink = pev->ltime + 0.1; - if ( m_iszSpawnObject ) - CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() ); - - - if ( Explodable() ) - { - ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE ); - } -} - - - -BOOL CBreakable :: IsBreakable( void ) -{ - return m_Material != matUnbreakableGlass; -} - - -int CBreakable :: DamageDecal( int bitsDamageType ) -{ - if ( m_Material == matGlass ) - return DECAL_GLASSBREAK1 + RANDOM_LONG(0,2); - - if ( m_Material == matUnbreakableGlass ) - return DECAL_BPROOF1; - - return CBaseEntity::DamageDecal( bitsDamageType ); -} - - -class CPushable : public CBreakable -{ -public: - void Spawn ( void ); - void Precache( void ); - void Touch ( CBaseEntity *pOther ); - void Move( CBaseEntity *pMover, int push ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT StopSound( void ); -// virtual void SetActivator( CBaseEntity *pActivator ) { m_pPusher = pActivator; } - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_CONTINUOUS_USE; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - inline float MaxSpeed( void ) { return m_maxSpeed; } - - // breakables use an overridden takedamage - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - - static TYPEDESCRIPTION m_SaveData[]; - - static const char *m_soundNames[3]; - int m_lastSound; // no need to save/restore, just keeps the same sound from playing twice in a row - float m_maxSpeed; - float m_soundTime; -}; - -TYPEDESCRIPTION CPushable::m_SaveData[] = -{ - DEFINE_FIELD( CPushable, m_maxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CPushable, m_soundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CPushable, CBreakable ); - -LINK_ENTITY_TO_CLASS( func_pushable, CPushable ); - -const char *CPushable :: m_soundNames[3] = { "debris/pushbox1.wav", "debris/pushbox2.wav", "debris/pushbox3.wav" }; - -void CPushable :: Spawn( void ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Spawn(); - else - Precache( ); - - pev->movetype = MOVETYPE_PUSHSTEP; - pev->solid = SOLID_BBOX; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - if ( pev->friction > 399 ) - pev->friction = 399; - - m_maxSpeed = 400 - pev->friction; - SetBits( pev->flags, FL_FLOAT ); - pev->friction = 0; - - pev->origin.z += 1; // Pick up off of the floor - UTIL_SetOrigin( pev, pev->origin ); - - // Multiply by area of the box's cross-section (assume 1000 units^3 standard volume) - pev->skin = static_cast(( pev->skin * (pev->maxs.x - pev->mins.x) * (pev->maxs.y - pev->mins.y) ) * 0.0005); - m_soundTime = 0; -} - - -void CPushable :: Precache( void ) -{ - for ( int i = 0; i < 3; i++ ) - PRECACHE_SOUND( m_soundNames[i] ); - - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - CBreakable::Precache( ); -} - - -void CPushable :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "size") ) - { - int bbox = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - switch( bbox ) - { - case 0: // Point - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - break; - - case 2: // Big Hull!?!? !!!BUGBUG Figure out what this hull really is - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN*2, VEC_DUCK_HULL_MAX*2); - break; - - case 3: // Player duck - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - break; - - default: - case 1: // Player - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - break; - } - - } - else if ( FStrEq(pkvd->szKeyName, "buoyancy") ) - { - pev->skin = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBreakable::KeyValue( pkvd ); -} - - -// Pull the func_pushable -void CPushable :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !pActivator || !pActivator->IsPlayer() ) - { - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - this->CBreakable::Use( pActivator, pCaller, useType, value ); - return; - } - - if ( pActivator->pev->velocity != g_vecZero ) - Move( pActivator, 0 ); -} - - -void CPushable :: Touch( CBaseEntity *pOther ) -{ - if ( FClassnameIs( pOther->pev, "worldspawn" ) ) - return; - - Move( pOther, 1 ); -} - - -void CPushable :: Move( CBaseEntity *pOther, int push ) -{ - entvars_t* pevToucher = pOther->pev; - int playerTouch = 0; - - // Is entity standing on this pushable ? - if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev ) - { - // Only push if floating - if ( pev->waterlevel > 0 ) - pev->velocity.z += pevToucher->velocity.z * 0.1; - - return; - } - - - if ( pOther->IsPlayer() ) - { - if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull) - return; - playerTouch = 1; - } - - float factor; - - if ( playerTouch ) - { - if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water - { - if ( pev->waterlevel < 1 ) - return; - else - factor = 0.1; - } - else - factor = 1; - } - else - factor = 0.25; - - pev->velocity.x += pevToucher->velocity.x * factor; - pev->velocity.y += pevToucher->velocity.y * factor; - - float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y ); - if ( push && (length > MaxSpeed()) ) - { - pev->velocity.x = (pev->velocity.x * MaxSpeed() / length ); - pev->velocity.y = (pev->velocity.y * MaxSpeed() / length ); - } - if ( playerTouch ) - { - pevToucher->velocity.x = pev->velocity.x; - pevToucher->velocity.y = pev->velocity.y; - if ( (gpGlobals->time - m_soundTime) > 0.7 ) - { - m_soundTime = gpGlobals->time; - if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) ) - { - m_lastSound = RANDOM_LONG(0,2); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM); - // SetThink( StopSound ); - // pev->nextthink = pev->ltime + 0.1; - } - else - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); - } - } -} - -#if 0 -void CPushable::StopSound( void ) -{ - Vector dist = pev->oldorigin - pev->origin; - if ( dist.Length() <= 0 ) - STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] ); -} -#endif - -int CPushable::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->spawnflags & SF_PUSH_BREAKABLE ) - return CBreakable::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); - - return 1; -} - diff --git a/sdk/dlls/func_break.h b/sdk/dlls/func_break.h deleted file mode 100644 index 9bb281d..0000000 --- a/sdk/dlls/func_break.h +++ /dev/null @@ -1,74 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef FUNC_BREAK_H -#define FUNC_BREAK_H - -typedef enum { expRandom, expDirected} Explosions; -typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; - -#define NUM_SHARDS 6 // this many shards spawned when breakable objects break; - -class CBreakable : public CBaseDelay -{ -public: - // basic functions - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT BreakTouch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void DamageSound( void ); - - // breakables use an overridden takedamage - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - // To spark when hit - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - - BOOL IsBreakable( void ); - BOOL SparkWhenHit( void ); - - int DamageDecal( int bitsDamageType ); - - void EXPORT Die( void ); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } - inline int ExplosionMagnitude( void ) { return pev->impulse; } - inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } - - static void MaterialSoundPrecache( Materials precacheMaterial ); - static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ); - static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); - - static const char *pSoundsWood[]; - static const char *pSoundsFlesh[]; - static const char *pSoundsGlass[]; - static const char *pSoundsMetal[]; - static const char *pSoundsConcrete[]; - static const char *pSpawnObjects[]; - - static TYPEDESCRIPTION m_SaveData[]; - - Materials m_Material; - Explosions m_Explosion; - int m_idShard; - float m_angle; - int m_iszGibModel; - int m_iszSpawnObject; -}; - -#endif // FUNC_BREAK_H diff --git a/sdk/dlls/func_tank.cpp b/sdk/dlls/func_tank.cpp deleted file mode 100644 index ddabf6a..0000000 --- a/sdk/dlls/func_tank.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "effects.h" -#include "weapons.h" -#include "explode.h" - -#include "player.h" - - -#define SF_TANK_ACTIVE 0x0001 -#define SF_TANK_PLAYER 0x0002 -#define SF_TANK_HUMANS 0x0004 -#define SF_TANK_ALIENS 0x0008 -#define SF_TANK_LINEOFSIGHT 0x0010 -#define SF_TANK_CANCONTROL 0x0020 -#define SF_TANK_SOUNDON 0x8000 - -enum TANKBULLET -{ - TANK_BULLET_NONE = 0, - TANK_BULLET_9MM = 1, - TANK_BULLET_MP5 = 2, - TANK_BULLET_12MM = 3, -}; - -// Custom damage -// env_laser (duration is 0.5 rate of fire) -// rockets -// explosion? - -class CFuncTank : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void TrackTarget( void ); - - virtual void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - virtual Vector UpdateTargetPosition( CBaseEntity *pTarget ) - { - return pTarget->BodyTarget( pev->origin ); - } - - void StartRotSound( void ); - void StopRotSound( void ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - inline BOOL IsActive( void ) { return (pev->spawnflags & SF_TANK_ACTIVE)?TRUE:FALSE; } - inline void TankActivate( void ) { pev->spawnflags |= SF_TANK_ACTIVE; pev->nextthink = pev->ltime + 0.1; m_fireLast = 0; } - inline void TankDeactivate( void ) { pev->spawnflags &= ~SF_TANK_ACTIVE; m_fireLast = 0; StopRotSound(); } - inline BOOL CanFire( void ) { return (gpGlobals->time - m_lastSightTime) < m_persist; } - BOOL InRange( float range ); - - // Acquire a target. pPlayer is a player in the PVS - edict_t *FindTarget( edict_t *pPlayer ); - - void TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ); - - Vector BarrelPosition( void ) - { - Vector forward, right, up; - UTIL_MakeVectorsPrivate( pev->angles, forward, right, up ); - return pev->origin + (forward * m_barrelPos.x) + (right * m_barrelPos.y) + (up * m_barrelPos.z); - } - - void AdjustAnglesForBarrel( Vector &angles, float distance ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BOOL OnControls( entvars_t *pevTest ); - BOOL StartControl( CBasePlayer* pController ); - void StopControl( void ); - void ControllerPostFrame( void ); - - -protected: - CBasePlayer* m_pController; - float m_flNextAttack; - Vector m_vecControllerUsePos; - - float m_yawCenter; // "Center" yaw - float m_yawRate; // Max turn rate to track targets - float m_yawRange; // Range of turning motion (one-sided: 30 is +/- 30 degress from center) - // Zero is full rotation - float m_yawTolerance; // Tolerance angle - - float m_pitchCenter; // "Center" pitch - float m_pitchRate; // Max turn rate on pitch - float m_pitchRange; // Range of pitch motion as above - float m_pitchTolerance; // Tolerance angle - - float m_fireLast; // Last time I fired - float m_fireRate; // How many rounds/second - float m_lastSightTime;// Last time I saw target - float m_persist; // Persistence of firing (how long do I shoot when I can't see) - float m_minRange; // Minimum range to aim/track - float m_maxRange; // Max range to aim/track - - Vector m_barrelPos; // Length of the freakin barrel - float m_spriteScale; // Scale of any sprites we shoot - int m_iszSpriteSmoke; - int m_iszSpriteFlash; - TANKBULLET m_bulletType; // Bullet type - int m_iBulletDamage; // 0 means use Bullet type's default damage - - Vector m_sightOrigin; // Last sight of target - int m_spread; // firing spread - int m_iszMaster; // Master entity (game_team_master or multisource) -}; - - -TYPEDESCRIPTION CFuncTank::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTank, m_yawCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_yawTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchCenter, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_pitchTolerance, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_fireLast, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_fireRate, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_lastSightTime, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_persist, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_minRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_maxRange, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_barrelPos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spriteScale, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTank, m_iszSpriteSmoke, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_iszSpriteFlash, FIELD_STRING ), - DEFINE_FIELD( CFuncTank, m_bulletType, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_sightOrigin, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_spread, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_pController, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTank, m_vecControllerUsePos, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTank, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CFuncTank, m_iBulletDamage, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTank, m_iszMaster, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTank, CBaseEntity ); - -static Vector gTankSpread[] = -{ - Vector( 0, 0, 0 ), // perfect - Vector( 0.025, 0.025, 0.025 ), // small cone - Vector( 0.05, 0.05, 0.05 ), // medium cone - Vector( 0.1, 0.1, 0.1 ), // large cone - Vector( 0.25, 0.25, 0.25 ), // extra-large cone -}; -#define MAX_FIRING_SPREADS ARRAYSIZE(gTankSpread) - - -void CFuncTank :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_PUSH; // so it doesn't get pushed by anything - pev->solid = SOLID_BSP; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_yawCenter = pev->angles.y; - m_pitchCenter = pev->angles.x; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; - - m_sightOrigin = BarrelPosition(); // Point at the end of the barrel - - if ( m_fireRate <= 0 ) - m_fireRate = 1; - if ( m_spread > static_cast(MAX_FIRING_SPREADS) ) - m_spread = 0; - - pev->oldorigin = pev->origin; -} - - -void CFuncTank :: Precache( void ) -{ - if ( m_iszSpriteSmoke ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteSmoke) ); - if ( m_iszSpriteFlash ) - PRECACHE_MODEL( (char *)STRING(m_iszSpriteFlash) ); - - if ( pev->noise ) - PRECACHE_SOUND( (char *)STRING(pev->noise) ); -} - - -void CFuncTank :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "yawrate")) - { - m_yawRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawrange")) - { - m_yawRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "yawtolerance")) - { - m_yawTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrange")) - { - m_pitchRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchrate")) - { - m_pitchRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitchtolerance")) - { - m_pitchTolerance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firerate")) - { - m_fireRate = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrel")) - { - m_barrelPos.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrely")) - { - m_barrelPos.y = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "barrelz")) - { - m_barrelPos.z = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritescale")) - { - m_spriteScale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spritesmoke")) - { - m_iszSpriteSmoke = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "spriteflash")) - { - m_iszSpriteFlash = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotatesound")) - { - pev->noise = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "persistence")) - { - m_persist = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bullet")) - { - m_bulletType = (TANKBULLET)atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bullet_damage" )) - { - m_iBulletDamage = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "firespread")) - { - m_spread = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "minRange")) - { - m_minRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "maxRange")) - { - m_maxRange = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_iszMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -////////////// START NEW STUFF ////////////// - -//================================================================================== -// TANK CONTROLLING -BOOL CFuncTank :: OnControls( entvars_t *pevTest ) -{ - if ( !(pev->spawnflags & SF_TANK_CANCONTROL) ) - return FALSE; - - if ( (m_vecControllerUsePos - pevTest->origin).Length() < 30 ) - return TRUE; - - return FALSE; -} - -BOOL CFuncTank :: StartControl( CBasePlayer *pController ) -{ - if ( m_pController != NULL ) - return FALSE; - - // Team only or disabled? - if ( m_iszMaster ) - { - if ( !UTIL_IsMasterTriggered( m_iszMaster, pController ) ) - return FALSE; - } - - ALERT( at_console, "using TANK!\n"); - - m_pController = pController; - if ( m_pController->m_pActiveItem ) - { - m_pController->m_pActiveItem->Holster(); - m_pController->pev->weaponmodel = 0; - m_pController->pev->viewmodel = 0; - - } - - m_pController->m_iHideHUD |= HIDEHUD_WEAPONS; - m_vecControllerUsePos = m_pController->pev->origin; - - pev->nextthink = pev->ltime + 0.1; - - return TRUE; -} - -void CFuncTank :: StopControl() -{ - // TODO: bring back the controllers current weapon - if ( !m_pController ) - return; - - if ( m_pController->m_pActiveItem ) - m_pController->m_pActiveItem->Deploy(); - - ALERT( at_console, "stopped using TANK\n"); - - m_pController->m_iHideHUD &= ~HIDEHUD_WEAPONS; - - pev->nextthink = 0; - m_pController = NULL; - - if ( IsActive() ) - pev->nextthink = pev->ltime + 1.0; -} - -// Called each frame by the player's ItemPostFrame -void CFuncTank :: ControllerPostFrame( void ) -{ - ASSERT(m_pController != NULL); - - if ( gpGlobals->time < m_flNextAttack ) - return; - - if ( m_pController->pev->button & IN_ATTACK ) - { - Vector vecForward; - UTIL_MakeVectorsPrivate( pev->angles, vecForward, NULL, NULL ); - - m_fireLast = gpGlobals->time - (1/m_fireRate) - 0.01; // to make sure the gun doesn't fire too many bullets - - Fire( BarrelPosition(), vecForward, m_pController->pev ); - - // HACKHACK -- make some noise (that the AI can hear) - if ( m_pController && m_pController->IsPlayer() ) - ((CBasePlayer *)m_pController)->m_iWeaponVolume = LOUD_GUN_VOLUME; - - m_flNextAttack = gpGlobals->time + (1/m_fireRate); - } -} -////////////// END NEW STUFF ////////////// - - -void CFuncTank :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TANK_CANCONTROL ) - { // player controlled turret - - if ( pActivator->Classify() != CLASS_PLAYER ) - return; - - if ( value == 2 && useType == USE_SET ) - { - ControllerPostFrame(); - } - else if ( !m_pController && useType != USE_OFF ) - { - ((CBasePlayer*)pActivator)->m_pTank = this; - StartControl( (CBasePlayer*)pActivator ); - } - else - { - StopControl(); - } - } - else - { - if ( !ShouldToggle( useType, IsActive() ) ) - return; - - if ( IsActive() ) - TankDeactivate(); - else - TankActivate(); - } -} - - -edict_t *CFuncTank :: FindTarget( edict_t *pPlayer ) -{ - return pPlayer; -} - - - -BOOL CFuncTank :: InRange( float range ) -{ - if ( range < m_minRange ) - return FALSE; - if ( m_maxRange > 0 && range > m_maxRange ) - return FALSE; - - return TRUE; -} - - -void CFuncTank :: Think( void ) -{ - pev->avelocity = g_vecZero; - TrackTarget(); - - if ( fabs(pev->avelocity.x) > 1 || fabs(pev->avelocity.y) > 1 ) - StartRotSound(); - else - StopRotSound(); -} - -void CFuncTank::TrackTarget( void ) -{ - TraceResult tr; - edict_t *pPlayer = FIND_CLIENT_IN_PVS( edict() ); - BOOL updateTime = FALSE; - Vector angles, direction, targetPosition, barrelEnd; - edict_t *pTarget = NULL; - - // Get a position to aim for - if (m_pController) - { - // Tanks attempt to mirror the player's angles - angles = m_pController->pev->v_angle; - angles[0] = 0 - angles[0]; - pev->nextthink = pev->ltime + 0.05; - } - else - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 0.1; - else - return; - - if ( FNullEnt( pPlayer ) ) - { - if ( IsActive() ) - pev->nextthink = pev->ltime + 2; // Wait 2 secs - return; - } - pTarget = FindTarget( pPlayer ); - if ( !pTarget ) - return; - - // Calculate angle needed to aim at target - barrelEnd = BarrelPosition(); - targetPosition = pTarget->v.origin + pTarget->v.view_ofs; - float range = (targetPosition - barrelEnd).Length(); - - if ( !InRange( range ) ) - return; - - UTIL_TraceLine( barrelEnd, targetPosition, dont_ignore_monsters, edict(), &tr ); - - // No line of sight, don't track - if ( tr.flFraction == 1.0 || tr.pHit == pTarget ) - { - CBaseEntity *pInstance = CBaseEntity::Instance(pTarget); - if ( InRange( range ) && pInstance && pInstance->IsAlive() ) - { - updateTime = TRUE; - m_sightOrigin = UpdateTargetPosition( pInstance ); - } - } - - // Track sight origin - -// !!! I'm not sure what i changed - direction = m_sightOrigin - pev->origin; -// direction = m_sightOrigin - barrelEnd; - angles = UTIL_VecToAngles( direction ); - - // Calculate the additional rotation to point the end of the barrel at the target (not the gun's center) - AdjustAnglesForBarrel( angles, direction.Length() ); - } - - angles.x = -angles.x; - - // Force the angles to be relative to the center position - angles.y = m_yawCenter + UTIL_AngleDistance( angles.y, m_yawCenter ); - angles.x = m_pitchCenter + UTIL_AngleDistance( angles.x, m_pitchCenter ); - - // Limit against range in y - if ( angles.y > m_yawCenter + m_yawRange ) - { - angles.y = m_yawCenter + m_yawRange; - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - else if ( angles.y < (m_yawCenter - m_yawRange) ) - { - angles.y = (m_yawCenter - m_yawRange); - updateTime = FALSE; // Don't update if you saw the player, but out of range - } - - if ( updateTime ) - m_lastSightTime = gpGlobals->time; - - // Move toward target at rate or less - float distY = UTIL_AngleDistance( angles.y, pev->angles.y ); - pev->avelocity.y = distY * 10; - if ( pev->avelocity.y > m_yawRate ) - pev->avelocity.y = m_yawRate; - else if ( pev->avelocity.y < -m_yawRate ) - pev->avelocity.y = -m_yawRate; - - // Limit against range in x - if ( angles.x > m_pitchCenter + m_pitchRange ) - angles.x = m_pitchCenter + m_pitchRange; - else if ( angles.x < m_pitchCenter - m_pitchRange ) - angles.x = m_pitchCenter - m_pitchRange; - - // Move toward target at rate or less - float distX = UTIL_AngleDistance( angles.x, pev->angles.x ); - pev->avelocity.x = distX * 10; - - if ( pev->avelocity.x > m_pitchRate ) - pev->avelocity.x = m_pitchRate; - else if ( pev->avelocity.x < -m_pitchRate ) - pev->avelocity.x = -m_pitchRate; - - if ( m_pController ) - return; - - if ( CanFire() && ( (fabs(distX) < m_pitchTolerance && fabs(distY) < m_yawTolerance) || (pev->spawnflags & SF_TANK_LINEOFSIGHT) ) ) - { - BOOL fire = FALSE; - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - if ( pev->spawnflags & SF_TANK_LINEOFSIGHT ) - { - float length = direction.Length(); - UTIL_TraceLine( barrelEnd, barrelEnd + forward * length, dont_ignore_monsters, edict(), &tr ); - if ( tr.pHit == pTarget ) - fire = TRUE; - } - else - fire = TRUE; - - if ( fire ) - { - Fire( BarrelPosition(), forward, pev ); - } - else - m_fireLast = 0; - } - else - m_fireLast = 0; -} - - -// If barrel is offset, add in additional rotation -void CFuncTank::AdjustAnglesForBarrel( Vector &angles, float distance ) -{ - float r2, d2; - - - if ( m_barrelPos.y != 0 || m_barrelPos.z != 0 ) - { - distance -= m_barrelPos.z; - d2 = distance * distance; - if ( m_barrelPos.y ) - { - r2 = m_barrelPos.y * m_barrelPos.y; - angles.y += (180.0 / M_PI) * atan2( m_barrelPos.y, sqrt( d2 - r2 ) ); - } - if ( m_barrelPos.z ) - { - r2 = m_barrelPos.z * m_barrelPos.z; - angles.x += (180.0 / M_PI) * atan2( -m_barrelPos.z, sqrt( d2 - r2 ) ); - } - } -} - - -// Fire targets and spawn sprites -void CFuncTank::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - if ( m_iszSpriteSmoke ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteSmoke), barrelEnd, TRUE ); - pSprite->AnimateAndDie( RANDOM_FLOAT( 15.0, 20.0 ) ); - pSprite->SetTransparency( kRenderTransAlpha, static_cast(pev->rendercolor.x), static_cast(pev->rendercolor.y), static_cast(pev->rendercolor.z), 255, kRenderFxNone ); - pSprite->pev->velocity.z = RANDOM_FLOAT(40, 80); - pSprite->SetScale( m_spriteScale ); - } - if ( m_iszSpriteFlash ) - { - CSprite *pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteFlash), barrelEnd, TRUE ); - pSprite->AnimateAndDie( 60 ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - pSprite->SetScale( m_spriteScale ); - - // Hack Hack, make it stick around for at least 100 ms. - pSprite->pev->nextthink += 0.1; - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - } - m_fireLast = gpGlobals->time; -} - - -void CFuncTank::TankTrace( const Vector &vecStart, const Vector &vecForward, const Vector &vecSpread, TraceResult &tr ) -{ - // get circular gaussian spread - float x, y, z; - do { - x = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - y = RANDOM_FLOAT(-0.5,0.5) + RANDOM_FLOAT(-0.5,0.5); - z = x*x+y*y; - } while (z > 1); - Vector vecDir = vecForward + - x * vecSpread.x * gpGlobals->v_right + - y * vecSpread.y * gpGlobals->v_up; - Vector vecEnd; - - vecEnd = vecStart + vecDir * 4096; - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &tr ); -} - - -void CFuncTank::StartRotSound( void ) -{ - if ( !pev->noise || (pev->spawnflags & SF_TANK_SOUNDON) ) - return; - pev->spawnflags |= SF_TANK_SOUNDON; - EMIT_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise), 0.85, ATTN_NORM); -} - - -void CFuncTank::StopRotSound( void ) -{ - if ( pev->spawnflags & SF_TANK_SOUNDON ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noise) ); - pev->spawnflags &= ~SF_TANK_SOUNDON; -} - -class CFuncTankGun : public CFuncTank -{ -public: - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tank, CFuncTankGun ); - -void CFuncTankGun::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - // FireBullets needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = static_cast((gpGlobals->time - m_fireLast) * m_fireRate); - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - switch( m_bulletType ) - { - case TANK_BULLET_9MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_9MM, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_MP5: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_MP5, 1, m_iBulletDamage, pevAttacker ); - break; - - case TANK_BULLET_12MM: - FireBullets( 1, barrelEnd, forward, gTankSpread[m_spread], 4096, BULLET_MONSTER_12MM, 1, m_iBulletDamage, pevAttacker ); - break; - - default: - case TANK_BULLET_NONE: - break; - } - } - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pevAttacker ); -} - - - -class CFuncTankLaser : public CFuncTank -{ -public: - void Activate( void ); - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); - void Think( void ); - CLaser *GetLaser( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CLaser *m_pLaser; - float m_laserTime; -}; -LINK_ENTITY_TO_CLASS( func_tanklaser, CFuncTankLaser ); - -TYPEDESCRIPTION CFuncTankLaser::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankLaser, m_pLaser, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTankLaser, m_laserTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankLaser, CFuncTank ); - -void CFuncTankLaser::Activate( void ) -{ - if ( !GetLaser() ) - { - UTIL_Remove(this); - ALERT( at_error, "Laser tank with no env_laser!\n" ); - } - else - { - m_pLaser->TurnOff(); - } -} - - -void CFuncTankLaser::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "laserentity")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -CLaser *CFuncTankLaser::GetLaser( void ) -{ - if ( m_pLaser ) - return m_pLaser; - - edict_t *pentLaser; - - pentLaser = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->message) ); - while ( !FNullEnt( pentLaser ) ) - { - // Found the landmark - if ( FClassnameIs( pentLaser, "env_laser" ) ) - { - m_pLaser = (CLaser *)CBaseEntity::Instance(pentLaser); - break; - } - else - pentLaser = FIND_ENTITY_BY_TARGETNAME( pentLaser, STRING(pev->message) ); - } - - return m_pLaser; -} - - -void CFuncTankLaser::Think( void ) -{ - if ( m_pLaser && (gpGlobals->time > m_laserTime) ) - m_pLaser->TurnOff(); - - CFuncTank::Think(); -} - - -void CFuncTankLaser::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - TraceResult tr; - - if ( m_fireLast != 0 && GetLaser() ) - { - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - int bulletCount = static_cast((gpGlobals->time - m_fireLast) * m_fireRate); - if ( bulletCount ) - { - for ( i = 0; i < bulletCount; i++ ) - { - m_pLaser->pev->origin = barrelEnd; - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - m_laserTime = gpGlobals->time; - m_pLaser->TurnOn(); - m_pLaser->pev->dmgtime = gpGlobals->time - 1.0; - m_pLaser->FireAtPoint( tr ); - m_pLaser->pev->nextthink = 0; - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - { - CFuncTank::Fire( barrelEnd, forward, pev ); - } -} - -class CFuncTankRocket : public CFuncTank -{ -public: - void Precache( void ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankrocket, CFuncTankRocket ); - -void CFuncTankRocket::Precache( void ) -{ - UTIL_PrecacheOther( "rpg_rocket" ); - CFuncTank::Precache(); -} - - - -void CFuncTankRocket::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - int i; - - if ( m_fireLast != 0 ) - { - int bulletCount = static_cast((gpGlobals->time - m_fireLast) * m_fireRate); - if ( bulletCount > 0 ) - { - for ( i = 0; i < bulletCount; i++ ) - { - CBaseEntity::Create( "rpg_rocket", barrelEnd, pev->angles, edict() ); - } - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - -class CFuncTankMortar : public CFuncTank -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ); -}; -LINK_ENTITY_TO_CLASS( func_tankmortar, CFuncTankMortar ); - - -void CFuncTankMortar::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "iMagnitude")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CFuncTank::KeyValue( pkvd ); -} - - -void CFuncTankMortar::Fire( const Vector &barrelEnd, const Vector &forward, entvars_t *pevAttacker ) -{ - if ( m_fireLast != 0 ) - { - int bulletCount = static_cast((gpGlobals->time - m_fireLast) * m_fireRate); - // Only create 1 explosion - if ( bulletCount > 0 ) - { - TraceResult tr; - - // TankTrace needs gpGlobals->v_up, etc. - UTIL_MakeAimVectors(pev->angles); - - TankTrace( barrelEnd, forward, gTankSpread[m_spread], tr ); - - ExplosionCreate( tr.vecEndPos, pev->angles, edict(), pev->impulse, TRUE ); - - CFuncTank::Fire( barrelEnd, forward, pev ); - } - } - else - CFuncTank::Fire( barrelEnd, forward, pev ); -} - - - -//============================================================================ -// FUNC TANK CONTROLS -//============================================================================ -class CFuncTankControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CFuncTank *m_pTank; -}; -LINK_ENTITY_TO_CLASS( func_tankcontrols, CFuncTankControls ); - -TYPEDESCRIPTION CFuncTankControls::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTankControls, m_pTank, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTankControls, CBaseEntity ); - -int CFuncTankControls :: ObjectCaps( void ) -{ - return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_IMPULSE_USE; -} - - -void CFuncTankControls :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ // pass the Use command onto the controls - if ( m_pTank ) - m_pTank->Use( pActivator, pCaller, useType, value ); - - ASSERT( m_pTank != NULL ); // if this fails, most likely means save/restore hasn't worked properly -} - - -void CFuncTankControls :: Think( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && strncmp( STRING(pTarget->v.classname), "func_tank", 9 ) ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No tank %s\n", STRING(pev->target) ); - return; - } - - m_pTank = (CFuncTank*)Instance(pTarget); -} - -void CFuncTankControls::Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NODRAW; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - pev->nextthink = gpGlobals->time + 0.3; // After all the func_tank's have spawned - - CBaseEntity::Spawn(); -} diff --git a/sdk/dlls/game.cpp b/sdk/dlls/game.cpp deleted file mode 100644 index 257daf3..0000000 --- a/sdk/dlls/game.cpp +++ /dev/null @@ -1,890 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "eiface.h" -#include "util.h" -#include "game.h" - -cvar_t displaysoundlist = {"displaysoundlist","0"}; - -// multiplayer server rules -cvar_t fragsleft = {"mp_fragsleft","0", FCVAR_SERVER | FCVAR_UNLOGGED }; // Don't spam console/log files/users with this changing -cvar_t timeleft = {"mp_timeleft","0" , FCVAR_SERVER | FCVAR_UNLOGGED }; // " " - -// multiplayer server rules -cvar_t teamplay = {"mp_teamplay","0", FCVAR_SERVER }; -cvar_t fraglimit = {"mp_fraglimit","0", FCVAR_SERVER }; -cvar_t timelimit = {"mp_timelimit","0", FCVAR_SERVER }; -cvar_t friendlyfire= {"mp_friendlyfire","0", FCVAR_SERVER }; -cvar_t falldamage = {"mp_falldamage","0", FCVAR_SERVER }; -cvar_t weaponstay = {"mp_weaponstay","0", FCVAR_SERVER }; -cvar_t forcerespawn= {"mp_forcerespawn","1", FCVAR_SERVER }; -cvar_t flashlight = {"mp_flashlight","0", FCVAR_SERVER }; -cvar_t aimcrosshair= {"mp_autocrosshair","1", FCVAR_SERVER }; -cvar_t decalfrequency = {"decalfrequency","30", FCVAR_SERVER }; -cvar_t teamlist = {"mp_teamlist","hgrunt;scientist", FCVAR_SERVER }; -cvar_t teamoverride = {"mp_teamoverride","1" }; -cvar_t defaultteam = {"mp_defaultteam","0" }; -cvar_t allowmonsters={"mp_allowmonsters","0", FCVAR_SERVER }; - -cvar_t allow_spectators = { "allow_spectators", "0.0", FCVAR_SERVER }; // 0 prevents players from being spectators - -cvar_t mp_chattime = {"mp_chattime","10", FCVAR_SERVER }; - -// Engine Cvars -cvar_t *g_psv_gravity = NULL; -cvar_t *g_psv_aim = NULL; -cvar_t *g_footsteps = NULL; - -//CVARS FOR SKILL LEVEL SETTINGS -// Agrunt -cvar_t sk_agrunt_health1 = {"sk_agrunt_health1","0"}; -cvar_t sk_agrunt_health2 = {"sk_agrunt_health2","0"}; -cvar_t sk_agrunt_health3 = {"sk_agrunt_health3","0"}; - -cvar_t sk_agrunt_dmg_punch1 = {"sk_agrunt_dmg_punch1","0"}; -cvar_t sk_agrunt_dmg_punch2 = {"sk_agrunt_dmg_punch2","0"}; -cvar_t sk_agrunt_dmg_punch3 = {"sk_agrunt_dmg_punch3","0"}; - -// Apache -cvar_t sk_apache_health1 = {"sk_apache_health1","0"}; -cvar_t sk_apache_health2 = {"sk_apache_health2","0"}; -cvar_t sk_apache_health3 = {"sk_apache_health3","0"}; - -// Barney -cvar_t sk_barney_health1 = {"sk_barney_health1","0"}; -cvar_t sk_barney_health2 = {"sk_barney_health2","0"}; -cvar_t sk_barney_health3 = {"sk_barney_health3","0"}; - -// Bullsquid -cvar_t sk_bullsquid_health1 = {"sk_bullsquid_health1","0"}; -cvar_t sk_bullsquid_health2 = {"sk_bullsquid_health2","0"}; -cvar_t sk_bullsquid_health3 = {"sk_bullsquid_health3","0"}; - -cvar_t sk_bullsquid_dmg_bite1 = {"sk_bullsquid_dmg_bite1","0"}; -cvar_t sk_bullsquid_dmg_bite2 = {"sk_bullsquid_dmg_bite2","0"}; -cvar_t sk_bullsquid_dmg_bite3 = {"sk_bullsquid_dmg_bite3","0"}; - -cvar_t sk_bullsquid_dmg_whip1 = {"sk_bullsquid_dmg_whip1","0"}; -cvar_t sk_bullsquid_dmg_whip2 = {"sk_bullsquid_dmg_whip2","0"}; -cvar_t sk_bullsquid_dmg_whip3 = {"sk_bullsquid_dmg_whip3","0"}; - -cvar_t sk_bullsquid_dmg_spit1 = {"sk_bullsquid_dmg_spit1","0"}; -cvar_t sk_bullsquid_dmg_spit2 = {"sk_bullsquid_dmg_spit2","0"}; -cvar_t sk_bullsquid_dmg_spit3 = {"sk_bullsquid_dmg_spit3","0"}; - - -// Big Momma -cvar_t sk_bigmomma_health_factor1 = {"sk_bigmomma_health_factor1","1.0"}; -cvar_t sk_bigmomma_health_factor2 = {"sk_bigmomma_health_factor2","1.0"}; -cvar_t sk_bigmomma_health_factor3 = {"sk_bigmomma_health_factor3","1.0"}; - -cvar_t sk_bigmomma_dmg_slash1 = {"sk_bigmomma_dmg_slash1","50"}; -cvar_t sk_bigmomma_dmg_slash2 = {"sk_bigmomma_dmg_slash2","50"}; -cvar_t sk_bigmomma_dmg_slash3 = {"sk_bigmomma_dmg_slash3","50"}; - -cvar_t sk_bigmomma_dmg_blast1 = {"sk_bigmomma_dmg_blast1","100"}; -cvar_t sk_bigmomma_dmg_blast2 = {"sk_bigmomma_dmg_blast2","100"}; -cvar_t sk_bigmomma_dmg_blast3 = {"sk_bigmomma_dmg_blast3","100"}; - -cvar_t sk_bigmomma_radius_blast1 = {"sk_bigmomma_radius_blast1","250"}; -cvar_t sk_bigmomma_radius_blast2 = {"sk_bigmomma_radius_blast2","250"}; -cvar_t sk_bigmomma_radius_blast3 = {"sk_bigmomma_radius_blast3","250"}; - -// Gargantua -cvar_t sk_gargantua_health1 = {"sk_gargantua_health1","0"}; -cvar_t sk_gargantua_health2 = {"sk_gargantua_health2","0"}; -cvar_t sk_gargantua_health3 = {"sk_gargantua_health3","0"}; - -cvar_t sk_gargantua_dmg_slash1 = {"sk_gargantua_dmg_slash1","0"}; -cvar_t sk_gargantua_dmg_slash2 = {"sk_gargantua_dmg_slash2","0"}; -cvar_t sk_gargantua_dmg_slash3 = {"sk_gargantua_dmg_slash3","0"}; - -cvar_t sk_gargantua_dmg_fire1 = {"sk_gargantua_dmg_fire1","0"}; -cvar_t sk_gargantua_dmg_fire2 = {"sk_gargantua_dmg_fire2","0"}; -cvar_t sk_gargantua_dmg_fire3 = {"sk_gargantua_dmg_fire3","0"}; - -cvar_t sk_gargantua_dmg_stomp1 = {"sk_gargantua_dmg_stomp1","0"}; -cvar_t sk_gargantua_dmg_stomp2 = {"sk_gargantua_dmg_stomp2","0"}; -cvar_t sk_gargantua_dmg_stomp3 = {"sk_gargantua_dmg_stomp3","0"}; - - -// Hassassin -cvar_t sk_hassassin_health1 = {"sk_hassassin_health1","0"}; -cvar_t sk_hassassin_health2 = {"sk_hassassin_health2","0"}; -cvar_t sk_hassassin_health3 = {"sk_hassassin_health3","0"}; - - -// Headcrab -cvar_t sk_headcrab_health1 = {"sk_headcrab_health1","0"}; -cvar_t sk_headcrab_health2 = {"sk_headcrab_health2","0"}; -cvar_t sk_headcrab_health3 = {"sk_headcrab_health3","0"}; - -cvar_t sk_headcrab_dmg_bite1 = {"sk_headcrab_dmg_bite1","0"}; -cvar_t sk_headcrab_dmg_bite2 = {"sk_headcrab_dmg_bite2","0"}; -cvar_t sk_headcrab_dmg_bite3 = {"sk_headcrab_dmg_bite3","0"}; - - -// Hgrunt -cvar_t sk_hgrunt_health1 = {"sk_hgrunt_health1","0"}; -cvar_t sk_hgrunt_health2 = {"sk_hgrunt_health2","0"}; -cvar_t sk_hgrunt_health3 = {"sk_hgrunt_health3","0"}; - -cvar_t sk_hgrunt_kick1 = {"sk_hgrunt_kick1","0"}; -cvar_t sk_hgrunt_kick2 = {"sk_hgrunt_kick2","0"}; -cvar_t sk_hgrunt_kick3 = {"sk_hgrunt_kick3","0"}; - -cvar_t sk_hgrunt_pellets1 = {"sk_hgrunt_pellets1","0"}; -cvar_t sk_hgrunt_pellets2 = {"sk_hgrunt_pellets2","0"}; -cvar_t sk_hgrunt_pellets3 = {"sk_hgrunt_pellets3","0"}; - -cvar_t sk_hgrunt_gspeed1 = {"sk_hgrunt_gspeed1","0"}; -cvar_t sk_hgrunt_gspeed2 = {"sk_hgrunt_gspeed2","0"}; -cvar_t sk_hgrunt_gspeed3 = {"sk_hgrunt_gspeed3","0"}; - -// Houndeye -cvar_t sk_houndeye_health1 = {"sk_houndeye_health1","0"}; -cvar_t sk_houndeye_health2 = {"sk_houndeye_health2","0"}; -cvar_t sk_houndeye_health3 = {"sk_houndeye_health3","0"}; - -cvar_t sk_houndeye_dmg_blast1 = {"sk_houndeye_dmg_blast1","0"}; -cvar_t sk_houndeye_dmg_blast2 = {"sk_houndeye_dmg_blast2","0"}; -cvar_t sk_houndeye_dmg_blast3 = {"sk_houndeye_dmg_blast3","0"}; - - -// ISlave -cvar_t sk_islave_health1 = {"sk_islave_health1","0"}; -cvar_t sk_islave_health2 = {"sk_islave_health2","0"}; -cvar_t sk_islave_health3 = {"sk_islave_health3","0"}; - -cvar_t sk_islave_dmg_claw1 = {"sk_islave_dmg_claw1","0"}; -cvar_t sk_islave_dmg_claw2 = {"sk_islave_dmg_claw2","0"}; -cvar_t sk_islave_dmg_claw3 = {"sk_islave_dmg_claw3","0"}; - -cvar_t sk_islave_dmg_clawrake1 = {"sk_islave_dmg_clawrake1","0"}; -cvar_t sk_islave_dmg_clawrake2 = {"sk_islave_dmg_clawrake2","0"}; -cvar_t sk_islave_dmg_clawrake3 = {"sk_islave_dmg_clawrake3","0"}; - -cvar_t sk_islave_dmg_zap1 = {"sk_islave_dmg_zap1","0"}; -cvar_t sk_islave_dmg_zap2 = {"sk_islave_dmg_zap2","0"}; -cvar_t sk_islave_dmg_zap3 = {"sk_islave_dmg_zap3","0"}; - - -// Icthyosaur -cvar_t sk_ichthyosaur_health1 = {"sk_ichthyosaur_health1","0"}; -cvar_t sk_ichthyosaur_health2 = {"sk_ichthyosaur_health2","0"}; -cvar_t sk_ichthyosaur_health3 = {"sk_ichthyosaur_health3","0"}; - -cvar_t sk_ichthyosaur_shake1 = {"sk_ichthyosaur_shake1","0"}; -cvar_t sk_ichthyosaur_shake2 = {"sk_ichthyosaur_shake2","0"}; -cvar_t sk_ichthyosaur_shake3 = {"sk_ichthyosaur_shake3","0"}; - - -// Leech -cvar_t sk_leech_health1 = {"sk_leech_health1","0"}; -cvar_t sk_leech_health2 = {"sk_leech_health2","0"}; -cvar_t sk_leech_health3 = {"sk_leech_health3","0"}; - -cvar_t sk_leech_dmg_bite1 = {"sk_leech_dmg_bite1","0"}; -cvar_t sk_leech_dmg_bite2 = {"sk_leech_dmg_bite2","0"}; -cvar_t sk_leech_dmg_bite3 = {"sk_leech_dmg_bite3","0"}; - -// Controller -cvar_t sk_controller_health1 = {"sk_controller_health1","0"}; -cvar_t sk_controller_health2 = {"sk_controller_health2","0"}; -cvar_t sk_controller_health3 = {"sk_controller_health3","0"}; - -cvar_t sk_controller_dmgzap1 = {"sk_controller_dmgzap1","0"}; -cvar_t sk_controller_dmgzap2 = {"sk_controller_dmgzap2","0"}; -cvar_t sk_controller_dmgzap3 = {"sk_controller_dmgzap3","0"}; - -cvar_t sk_controller_speedball1 = {"sk_controller_speedball1","0"}; -cvar_t sk_controller_speedball2 = {"sk_controller_speedball2","0"}; -cvar_t sk_controller_speedball3 = {"sk_controller_speedball3","0"}; - -cvar_t sk_controller_dmgball1 = {"sk_controller_dmgball1","0"}; -cvar_t sk_controller_dmgball2 = {"sk_controller_dmgball2","0"}; -cvar_t sk_controller_dmgball3 = {"sk_controller_dmgball3","0"}; - -// Nihilanth -cvar_t sk_nihilanth_health1 = {"sk_nihilanth_health1","0"}; -cvar_t sk_nihilanth_health2 = {"sk_nihilanth_health2","0"}; -cvar_t sk_nihilanth_health3 = {"sk_nihilanth_health3","0"}; - -cvar_t sk_nihilanth_zap1 = {"sk_nihilanth_zap1","0"}; -cvar_t sk_nihilanth_zap2 = {"sk_nihilanth_zap2","0"}; -cvar_t sk_nihilanth_zap3 = {"sk_nihilanth_zap3","0"}; - -// Scientist -cvar_t sk_scientist_health1 = {"sk_scientist_health1","0"}; -cvar_t sk_scientist_health2 = {"sk_scientist_health2","0"}; -cvar_t sk_scientist_health3 = {"sk_scientist_health3","0"}; - - -// Snark -cvar_t sk_snark_health1 = {"sk_snark_health1","0"}; -cvar_t sk_snark_health2 = {"sk_snark_health2","0"}; -cvar_t sk_snark_health3 = {"sk_snark_health3","0"}; - -cvar_t sk_snark_dmg_bite1 = {"sk_snark_dmg_bite1","0"}; -cvar_t sk_snark_dmg_bite2 = {"sk_snark_dmg_bite2","0"}; -cvar_t sk_snark_dmg_bite3 = {"sk_snark_dmg_bite3","0"}; - -cvar_t sk_snark_dmg_pop1 = {"sk_snark_dmg_pop1","0"}; -cvar_t sk_snark_dmg_pop2 = {"sk_snark_dmg_pop2","0"}; -cvar_t sk_snark_dmg_pop3 = {"sk_snark_dmg_pop3","0"}; - - - -// Zombie -cvar_t sk_zombie_health1 = {"sk_zombie_health1","0"}; -cvar_t sk_zombie_health2 = {"sk_zombie_health2","0"}; -cvar_t sk_zombie_health3 = {"sk_zombie_health3","0"}; - -cvar_t sk_zombie_dmg_one_slash1 = {"sk_zombie_dmg_one_slash1","0"}; -cvar_t sk_zombie_dmg_one_slash2 = {"sk_zombie_dmg_one_slash2","0"}; -cvar_t sk_zombie_dmg_one_slash3 = {"sk_zombie_dmg_one_slash3","0"}; - -cvar_t sk_zombie_dmg_both_slash1 = {"sk_zombie_dmg_both_slash1","0"}; -cvar_t sk_zombie_dmg_both_slash2 = {"sk_zombie_dmg_both_slash2","0"}; -cvar_t sk_zombie_dmg_both_slash3 = {"sk_zombie_dmg_both_slash3","0"}; - - -//Turret -cvar_t sk_turret_health1 = {"sk_turret_health1","0"}; -cvar_t sk_turret_health2 = {"sk_turret_health2","0"}; -cvar_t sk_turret_health3 = {"sk_turret_health3","0"}; - - -// MiniTurret -cvar_t sk_miniturret_health1 = {"sk_miniturret_health1","0"}; -cvar_t sk_miniturret_health2 = {"sk_miniturret_health2","0"}; -cvar_t sk_miniturret_health3 = {"sk_miniturret_health3","0"}; - - -// Sentry Turret -cvar_t sk_sentry_health1 = {"sk_sentry_health1","0"}; -cvar_t sk_sentry_health2 = {"sk_sentry_health2","0"}; -cvar_t sk_sentry_health3 = {"sk_sentry_health3","0"}; - - -// PLAYER WEAPONS - -// Crowbar whack -cvar_t sk_plr_crowbar1 = {"sk_plr_crowbar1","0"}; -cvar_t sk_plr_crowbar2 = {"sk_plr_crowbar2","0"}; -cvar_t sk_plr_crowbar3 = {"sk_plr_crowbar3","0"}; - -// Glock Round -cvar_t sk_plr_9mm_bullet1 = {"sk_plr_9mm_bullet1","0"}; -cvar_t sk_plr_9mm_bullet2 = {"sk_plr_9mm_bullet2","0"}; -cvar_t sk_plr_9mm_bullet3 = {"sk_plr_9mm_bullet3","0"}; - -// 357 Round -cvar_t sk_plr_357_bullet1 = {"sk_plr_357_bullet1","0"}; -cvar_t sk_plr_357_bullet2 = {"sk_plr_357_bullet2","0"}; -cvar_t sk_plr_357_bullet3 = {"sk_plr_357_bullet3","0"}; - -// MP5 Round -cvar_t sk_plr_9mmAR_bullet1 = {"sk_plr_9mmAR_bullet1","0"}; -cvar_t sk_plr_9mmAR_bullet2 = {"sk_plr_9mmAR_bullet2","0"}; -cvar_t sk_plr_9mmAR_bullet3 = {"sk_plr_9mmAR_bullet3","0"}; - - -// M203 grenade -cvar_t sk_plr_9mmAR_grenade1 = {"sk_plr_9mmAR_grenade1","0"}; -cvar_t sk_plr_9mmAR_grenade2 = {"sk_plr_9mmAR_grenade2","0"}; -cvar_t sk_plr_9mmAR_grenade3 = {"sk_plr_9mmAR_grenade3","0"}; - - -// Shotgun buckshot -cvar_t sk_plr_buckshot1 = {"sk_plr_buckshot1","0"}; -cvar_t sk_plr_buckshot2 = {"sk_plr_buckshot2","0"}; -cvar_t sk_plr_buckshot3 = {"sk_plr_buckshot3","0"}; - - -// Crossbow -cvar_t sk_plr_xbow_bolt_client1 = {"sk_plr_xbow_bolt_client1","0"}; -cvar_t sk_plr_xbow_bolt_client2 = {"sk_plr_xbow_bolt_client2","0"}; -cvar_t sk_plr_xbow_bolt_client3 = {"sk_plr_xbow_bolt_client3","0"}; - -cvar_t sk_plr_xbow_bolt_monster1 = {"sk_plr_xbow_bolt_monster1","0"}; -cvar_t sk_plr_xbow_bolt_monster2 = {"sk_plr_xbow_bolt_monster2","0"}; -cvar_t sk_plr_xbow_bolt_monster3 = {"sk_plr_xbow_bolt_monster3","0"}; - - -// RPG -cvar_t sk_plr_rpg1 = {"sk_plr_rpg1","0"}; -cvar_t sk_plr_rpg2 = {"sk_plr_rpg2","0"}; -cvar_t sk_plr_rpg3 = {"sk_plr_rpg3","0"}; - - -// Zero Point Generator -cvar_t sk_plr_gauss1 = {"sk_plr_gauss1","0"}; -cvar_t sk_plr_gauss2 = {"sk_plr_gauss2","0"}; -cvar_t sk_plr_gauss3 = {"sk_plr_gauss3","0"}; - - -// Tau Cannon -cvar_t sk_plr_egon_narrow1 = {"sk_plr_egon_narrow1","0"}; -cvar_t sk_plr_egon_narrow2 = {"sk_plr_egon_narrow2","0"}; -cvar_t sk_plr_egon_narrow3 = {"sk_plr_egon_narrow3","0"}; - -cvar_t sk_plr_egon_wide1 = {"sk_plr_egon_wide1","0"}; -cvar_t sk_plr_egon_wide2 = {"sk_plr_egon_wide2","0"}; -cvar_t sk_plr_egon_wide3 = {"sk_plr_egon_wide3","0"}; - - -// Hand Grendade -cvar_t sk_plr_hand_grenade1 = {"sk_plr_hand_grenade1","0"}; -cvar_t sk_plr_hand_grenade2 = {"sk_plr_hand_grenade2","0"}; -cvar_t sk_plr_hand_grenade3 = {"sk_plr_hand_grenade3","0"}; - - -// Satchel Charge -cvar_t sk_plr_satchel1 = {"sk_plr_satchel1","0"}; -cvar_t sk_plr_satchel2 = {"sk_plr_satchel2","0"}; -cvar_t sk_plr_satchel3 = {"sk_plr_satchel3","0"}; - - -// Tripmine -cvar_t sk_plr_tripmine1 = {"sk_plr_tripmine1","0"}; -cvar_t sk_plr_tripmine2 = {"sk_plr_tripmine2","0"}; -cvar_t sk_plr_tripmine3 = {"sk_plr_tripmine3","0"}; - - -// WORLD WEAPONS -cvar_t sk_12mm_bullet1 = {"sk_12mm_bullet1","0"}; -cvar_t sk_12mm_bullet2 = {"sk_12mm_bullet2","0"}; -cvar_t sk_12mm_bullet3 = {"sk_12mm_bullet3","0"}; - -cvar_t sk_9mmAR_bullet1 = {"sk_9mmAR_bullet1","0"}; -cvar_t sk_9mmAR_bullet2 = {"sk_9mmAR_bullet2","0"}; -cvar_t sk_9mmAR_bullet3 = {"sk_9mmAR_bullet3","0"}; - -cvar_t sk_9mm_bullet1 = {"sk_9mm_bullet1","0"}; -cvar_t sk_9mm_bullet2 = {"sk_9mm_bullet2","0"}; -cvar_t sk_9mm_bullet3 = {"sk_9mm_bullet3","0"}; - - -// HORNET -cvar_t sk_hornet_dmg1 = {"sk_hornet_dmg1","0"}; -cvar_t sk_hornet_dmg2 = {"sk_hornet_dmg2","0"}; -cvar_t sk_hornet_dmg3 = {"sk_hornet_dmg3","0"}; - -// HEALTH/CHARGE -cvar_t sk_suitcharger1 = { "sk_suitcharger1","0" }; -cvar_t sk_suitcharger2 = { "sk_suitcharger2","0" }; -cvar_t sk_suitcharger3 = { "sk_suitcharger3","0" }; - -cvar_t sk_battery1 = { "sk_battery1","0" }; -cvar_t sk_battery2 = { "sk_battery2","0" }; -cvar_t sk_battery3 = { "sk_battery3","0" }; - -cvar_t sk_healthcharger1 = { "sk_healthcharger1","0" }; -cvar_t sk_healthcharger2 = { "sk_healthcharger2","0" }; -cvar_t sk_healthcharger3 = { "sk_healthcharger3","0" }; - -cvar_t sk_healthkit1 = { "sk_healthkit1","0" }; -cvar_t sk_healthkit2 = { "sk_healthkit2","0" }; -cvar_t sk_healthkit3 = { "sk_healthkit3","0" }; - -cvar_t sk_scientist_heal1 = { "sk_scientist_heal1","0" }; -cvar_t sk_scientist_heal2 = { "sk_scientist_heal2","0" }; -cvar_t sk_scientist_heal3 = { "sk_scientist_heal3","0" }; - - -// monster damage adjusters -cvar_t sk_monster_head1 = { "sk_monster_head1","2" }; -cvar_t sk_monster_head2 = { "sk_monster_head2","2" }; -cvar_t sk_monster_head3 = { "sk_monster_head3","2" }; - -cvar_t sk_monster_chest1 = { "sk_monster_chest1","1" }; -cvar_t sk_monster_chest2 = { "sk_monster_chest2","1" }; -cvar_t sk_monster_chest3 = { "sk_monster_chest3","1" }; - -cvar_t sk_monster_stomach1 = { "sk_monster_stomach1","1" }; -cvar_t sk_monster_stomach2 = { "sk_monster_stomach2","1" }; -cvar_t sk_monster_stomach3 = { "sk_monster_stomach3","1" }; - -cvar_t sk_monster_arm1 = { "sk_monster_arm1","1" }; -cvar_t sk_monster_arm2 = { "sk_monster_arm2","1" }; -cvar_t sk_monster_arm3 = { "sk_monster_arm3","1" }; - -cvar_t sk_monster_leg1 = { "sk_monster_leg1","1" }; -cvar_t sk_monster_leg2 = { "sk_monster_leg2","1" }; -cvar_t sk_monster_leg3 = { "sk_monster_leg3","1" }; - -// player damage adjusters -cvar_t sk_player_head1 = { "sk_player_head1","2" }; -cvar_t sk_player_head2 = { "sk_player_head2","2" }; -cvar_t sk_player_head3 = { "sk_player_head3","2" }; - -cvar_t sk_player_chest1 = { "sk_player_chest1","1" }; -cvar_t sk_player_chest2 = { "sk_player_chest2","1" }; -cvar_t sk_player_chest3 = { "sk_player_chest3","1" }; - -cvar_t sk_player_stomach1 = { "sk_player_stomach1","1" }; -cvar_t sk_player_stomach2 = { "sk_player_stomach2","1" }; -cvar_t sk_player_stomach3 = { "sk_player_stomach3","1" }; - -cvar_t sk_player_arm1 = { "sk_player_arm1","1" }; -cvar_t sk_player_arm2 = { "sk_player_arm2","1" }; -cvar_t sk_player_arm3 = { "sk_player_arm3","1" }; - -cvar_t sk_player_leg1 = { "sk_player_leg1","1" }; -cvar_t sk_player_leg2 = { "sk_player_leg2","1" }; -cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; - -// END Cvars for Skill Level settings - -// Register your console variables here -// This gets called one time when the game is initialied -void GameDLLInit( void ) -{ - // Register cvars here: - - g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); - g_psv_aim = CVAR_GET_POINTER( "sv_aim" ); - g_footsteps = CVAR_GET_POINTER( "mp_footsteps" ); - - CVAR_REGISTER (&displaysoundlist); - CVAR_REGISTER( &allow_spectators ); - - CVAR_REGISTER (&teamplay); - CVAR_REGISTER (&fraglimit); - CVAR_REGISTER (&timelimit); - - CVAR_REGISTER (&fragsleft); - CVAR_REGISTER (&timeleft); - - CVAR_REGISTER (&friendlyfire); - CVAR_REGISTER (&falldamage); - CVAR_REGISTER (&weaponstay); - CVAR_REGISTER (&forcerespawn); - CVAR_REGISTER (&flashlight); - CVAR_REGISTER (&aimcrosshair); - CVAR_REGISTER (&decalfrequency); - CVAR_REGISTER (&teamlist); - CVAR_REGISTER (&teamoverride); - CVAR_REGISTER (&defaultteam); - CVAR_REGISTER (&allowmonsters); - - CVAR_REGISTER (&mp_chattime); - -// REGISTER CVARS FOR SKILL LEVEL STUFF - // Agrunt - CVAR_REGISTER ( &sk_agrunt_health1 );// {"sk_agrunt_health1","0"}; - CVAR_REGISTER ( &sk_agrunt_health2 );// {"sk_agrunt_health2","0"}; - CVAR_REGISTER ( &sk_agrunt_health3 );// {"sk_agrunt_health3","0"}; - - CVAR_REGISTER ( &sk_agrunt_dmg_punch1 );// {"sk_agrunt_dmg_punch1","0"}; - CVAR_REGISTER ( &sk_agrunt_dmg_punch2 );// {"sk_agrunt_dmg_punch2","0"}; - CVAR_REGISTER ( &sk_agrunt_dmg_punch3 );// {"sk_agrunt_dmg_punch3","0"}; - - // Apache - CVAR_REGISTER ( &sk_apache_health1 );// {"sk_apache_health1","0"}; - CVAR_REGISTER ( &sk_apache_health2 );// {"sk_apache_health2","0"}; - CVAR_REGISTER ( &sk_apache_health3 );// {"sk_apache_health3","0"}; - - // Barney - CVAR_REGISTER ( &sk_barney_health1 );// {"sk_barney_health1","0"}; - CVAR_REGISTER ( &sk_barney_health2 );// {"sk_barney_health2","0"}; - CVAR_REGISTER ( &sk_barney_health3 );// {"sk_barney_health3","0"}; - - // Bullsquid - CVAR_REGISTER ( &sk_bullsquid_health1 );// {"sk_bullsquid_health1","0"}; - CVAR_REGISTER ( &sk_bullsquid_health2 );// {"sk_bullsquid_health2","0"}; - CVAR_REGISTER ( &sk_bullsquid_health3 );// {"sk_bullsquid_health3","0"}; - - CVAR_REGISTER ( &sk_bullsquid_dmg_bite1 );// {"sk_bullsquid_dmg_bite1","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_bite2 );// {"sk_bullsquid_dmg_bite2","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_bite3 );// {"sk_bullsquid_dmg_bite3","0"}; - - CVAR_REGISTER ( &sk_bullsquid_dmg_whip1 );// {"sk_bullsquid_dmg_whip1","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_whip2 );// {"sk_bullsquid_dmg_whip2","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_whip3 );// {"sk_bullsquid_dmg_whip3","0"}; - - CVAR_REGISTER ( &sk_bullsquid_dmg_spit1 );// {"sk_bullsquid_dmg_spit1","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_spit2 );// {"sk_bullsquid_dmg_spit2","0"}; - CVAR_REGISTER ( &sk_bullsquid_dmg_spit3 );// {"sk_bullsquid_dmg_spit3","0"}; - - - CVAR_REGISTER ( &sk_bigmomma_health_factor1 );// {"sk_bigmomma_health_factor1","1.0"}; - CVAR_REGISTER ( &sk_bigmomma_health_factor2 );// {"sk_bigmomma_health_factor2","1.0"}; - CVAR_REGISTER ( &sk_bigmomma_health_factor3 );// {"sk_bigmomma_health_factor3","1.0"}; - - CVAR_REGISTER ( &sk_bigmomma_dmg_slash1 );// {"sk_bigmomma_dmg_slash1","50"}; - CVAR_REGISTER ( &sk_bigmomma_dmg_slash2 );// {"sk_bigmomma_dmg_slash2","50"}; - CVAR_REGISTER ( &sk_bigmomma_dmg_slash3 );// {"sk_bigmomma_dmg_slash3","50"}; - - CVAR_REGISTER ( &sk_bigmomma_dmg_blast1 );// {"sk_bigmomma_dmg_blast1","100"}; - CVAR_REGISTER ( &sk_bigmomma_dmg_blast2 );// {"sk_bigmomma_dmg_blast2","100"}; - CVAR_REGISTER ( &sk_bigmomma_dmg_blast3 );// {"sk_bigmomma_dmg_blast3","100"}; - - CVAR_REGISTER ( &sk_bigmomma_radius_blast1 );// {"sk_bigmomma_radius_blast1","250"}; - CVAR_REGISTER ( &sk_bigmomma_radius_blast2 );// {"sk_bigmomma_radius_blast2","250"}; - CVAR_REGISTER ( &sk_bigmomma_radius_blast3 );// {"sk_bigmomma_radius_blast3","250"}; - - // Gargantua - CVAR_REGISTER ( &sk_gargantua_health1 );// {"sk_gargantua_health1","0"}; - CVAR_REGISTER ( &sk_gargantua_health2 );// {"sk_gargantua_health2","0"}; - CVAR_REGISTER ( &sk_gargantua_health3 );// {"sk_gargantua_health3","0"}; - - CVAR_REGISTER ( &sk_gargantua_dmg_slash1 );// {"sk_gargantua_dmg_slash1","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_slash2 );// {"sk_gargantua_dmg_slash2","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_slash3 );// {"sk_gargantua_dmg_slash3","0"}; - - CVAR_REGISTER ( &sk_gargantua_dmg_fire1 );// {"sk_gargantua_dmg_fire1","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_fire2 );// {"sk_gargantua_dmg_fire2","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_fire3 );// {"sk_gargantua_dmg_fire3","0"}; - - CVAR_REGISTER ( &sk_gargantua_dmg_stomp1 );// {"sk_gargantua_dmg_stomp1","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_stomp2 );// {"sk_gargantua_dmg_stomp2","0"}; - CVAR_REGISTER ( &sk_gargantua_dmg_stomp3 );// {"sk_gargantua_dmg_stomp3","0"}; - - - // Hassassin - CVAR_REGISTER ( &sk_hassassin_health1 );// {"sk_hassassin_health1","0"}; - CVAR_REGISTER ( &sk_hassassin_health2 );// {"sk_hassassin_health2","0"}; - CVAR_REGISTER ( &sk_hassassin_health3 );// {"sk_hassassin_health3","0"}; - - - // Headcrab - CVAR_REGISTER ( &sk_headcrab_health1 );// {"sk_headcrab_health1","0"}; - CVAR_REGISTER ( &sk_headcrab_health2 );// {"sk_headcrab_health2","0"}; - CVAR_REGISTER ( &sk_headcrab_health3 );// {"sk_headcrab_health3","0"}; - - CVAR_REGISTER ( &sk_headcrab_dmg_bite1 );// {"sk_headcrab_dmg_bite1","0"}; - CVAR_REGISTER ( &sk_headcrab_dmg_bite2 );// {"sk_headcrab_dmg_bite2","0"}; - CVAR_REGISTER ( &sk_headcrab_dmg_bite3 );// {"sk_headcrab_dmg_bite3","0"}; - - - // Hgrunt - CVAR_REGISTER ( &sk_hgrunt_health1 );// {"sk_hgrunt_health1","0"}; - CVAR_REGISTER ( &sk_hgrunt_health2 );// {"sk_hgrunt_health2","0"}; - CVAR_REGISTER ( &sk_hgrunt_health3 );// {"sk_hgrunt_health3","0"}; - - CVAR_REGISTER ( &sk_hgrunt_kick1 );// {"sk_hgrunt_kick1","0"}; - CVAR_REGISTER ( &sk_hgrunt_kick2 );// {"sk_hgrunt_kick2","0"}; - CVAR_REGISTER ( &sk_hgrunt_kick3 );// {"sk_hgrunt_kick3","0"}; - - CVAR_REGISTER ( &sk_hgrunt_pellets1 ); - CVAR_REGISTER ( &sk_hgrunt_pellets2 ); - CVAR_REGISTER ( &sk_hgrunt_pellets3 ); - - CVAR_REGISTER ( &sk_hgrunt_gspeed1 ); - CVAR_REGISTER ( &sk_hgrunt_gspeed2 ); - CVAR_REGISTER ( &sk_hgrunt_gspeed3 ); - - // Houndeye - CVAR_REGISTER ( &sk_houndeye_health1 );// {"sk_houndeye_health1","0"}; - CVAR_REGISTER ( &sk_houndeye_health2 );// {"sk_houndeye_health2","0"}; - CVAR_REGISTER ( &sk_houndeye_health3 );// {"sk_houndeye_health3","0"}; - - CVAR_REGISTER ( &sk_houndeye_dmg_blast1 );// {"sk_houndeye_dmg_blast1","0"}; - CVAR_REGISTER ( &sk_houndeye_dmg_blast2 );// {"sk_houndeye_dmg_blast2","0"}; - CVAR_REGISTER ( &sk_houndeye_dmg_blast3 );// {"sk_houndeye_dmg_blast3","0"}; - - - // ISlave - CVAR_REGISTER ( &sk_islave_health1 );// {"sk_islave_health1","0"}; - CVAR_REGISTER ( &sk_islave_health2 );// {"sk_islave_health2","0"}; - CVAR_REGISTER ( &sk_islave_health3 );// {"sk_islave_health3","0"}; - - CVAR_REGISTER ( &sk_islave_dmg_claw1 );// {"sk_islave_dmg_claw1","0"}; - CVAR_REGISTER ( &sk_islave_dmg_claw2 );// {"sk_islave_dmg_claw2","0"}; - CVAR_REGISTER ( &sk_islave_dmg_claw3 );// {"sk_islave_dmg_claw3","0"}; - - CVAR_REGISTER ( &sk_islave_dmg_clawrake1 );// {"sk_islave_dmg_clawrake1","0"}; - CVAR_REGISTER ( &sk_islave_dmg_clawrake2 );// {"sk_islave_dmg_clawrake2","0"}; - CVAR_REGISTER ( &sk_islave_dmg_clawrake3 );// {"sk_islave_dmg_clawrake3","0"}; - - CVAR_REGISTER ( &sk_islave_dmg_zap1 );// {"sk_islave_dmg_zap1","0"}; - CVAR_REGISTER ( &sk_islave_dmg_zap2 );// {"sk_islave_dmg_zap2","0"}; - CVAR_REGISTER ( &sk_islave_dmg_zap3 );// {"sk_islave_dmg_zap3","0"}; - - - // Icthyosaur - CVAR_REGISTER ( &sk_ichthyosaur_health1 );// {"sk_ichthyosaur_health1","0"}; - CVAR_REGISTER ( &sk_ichthyosaur_health2 );// {"sk_ichthyosaur_health2","0"}; - CVAR_REGISTER ( &sk_ichthyosaur_health3 );// {"sk_ichthyosaur_health3","0"}; - - CVAR_REGISTER ( &sk_ichthyosaur_shake1 );// {"sk_ichthyosaur_health3","0"}; - CVAR_REGISTER ( &sk_ichthyosaur_shake2 );// {"sk_ichthyosaur_health3","0"}; - CVAR_REGISTER ( &sk_ichthyosaur_shake3 );// {"sk_ichthyosaur_health3","0"}; - - - - // Leech - CVAR_REGISTER ( &sk_leech_health1 );// {"sk_leech_health1","0"}; - CVAR_REGISTER ( &sk_leech_health2 );// {"sk_leech_health2","0"}; - CVAR_REGISTER ( &sk_leech_health3 );// {"sk_leech_health3","0"}; - - CVAR_REGISTER ( &sk_leech_dmg_bite1 );// {"sk_leech_dmg_bite1","0"}; - CVAR_REGISTER ( &sk_leech_dmg_bite2 );// {"sk_leech_dmg_bite2","0"}; - CVAR_REGISTER ( &sk_leech_dmg_bite3 );// {"sk_leech_dmg_bite3","0"}; - - - // Controller - CVAR_REGISTER ( &sk_controller_health1 ); - CVAR_REGISTER ( &sk_controller_health2 ); - CVAR_REGISTER ( &sk_controller_health3 ); - - CVAR_REGISTER ( &sk_controller_dmgzap1 ); - CVAR_REGISTER ( &sk_controller_dmgzap2 ); - CVAR_REGISTER ( &sk_controller_dmgzap3 ); - - CVAR_REGISTER ( &sk_controller_speedball1 ); - CVAR_REGISTER ( &sk_controller_speedball2 ); - CVAR_REGISTER ( &sk_controller_speedball3 ); - - CVAR_REGISTER ( &sk_controller_dmgball1 ); - CVAR_REGISTER ( &sk_controller_dmgball2 ); - CVAR_REGISTER ( &sk_controller_dmgball3 ); - - // Nihilanth - CVAR_REGISTER ( &sk_nihilanth_health1 );// {"sk_nihilanth_health1","0"}; - CVAR_REGISTER ( &sk_nihilanth_health2 );// {"sk_nihilanth_health2","0"}; - CVAR_REGISTER ( &sk_nihilanth_health3 );// {"sk_nihilanth_health3","0"}; - - CVAR_REGISTER ( &sk_nihilanth_zap1 ); - CVAR_REGISTER ( &sk_nihilanth_zap2 ); - CVAR_REGISTER ( &sk_nihilanth_zap3 ); - - // Scientist - CVAR_REGISTER ( &sk_scientist_health1 );// {"sk_scientist_health1","0"}; - CVAR_REGISTER ( &sk_scientist_health2 );// {"sk_scientist_health2","0"}; - CVAR_REGISTER ( &sk_scientist_health3 );// {"sk_scientist_health3","0"}; - - - // Snark - CVAR_REGISTER ( &sk_snark_health1 );// {"sk_snark_health1","0"}; - CVAR_REGISTER ( &sk_snark_health2 );// {"sk_snark_health2","0"}; - CVAR_REGISTER ( &sk_snark_health3 );// {"sk_snark_health3","0"}; - - CVAR_REGISTER ( &sk_snark_dmg_bite1 );// {"sk_snark_dmg_bite1","0"}; - CVAR_REGISTER ( &sk_snark_dmg_bite2 );// {"sk_snark_dmg_bite2","0"}; - CVAR_REGISTER ( &sk_snark_dmg_bite3 );// {"sk_snark_dmg_bite3","0"}; - - CVAR_REGISTER ( &sk_snark_dmg_pop1 );// {"sk_snark_dmg_pop1","0"}; - CVAR_REGISTER ( &sk_snark_dmg_pop2 );// {"sk_snark_dmg_pop2","0"}; - CVAR_REGISTER ( &sk_snark_dmg_pop3 );// {"sk_snark_dmg_pop3","0"}; - - - - // Zombie - CVAR_REGISTER ( &sk_zombie_health1 );// {"sk_zombie_health1","0"}; - CVAR_REGISTER ( &sk_zombie_health2 );// {"sk_zombie_health3","0"}; - CVAR_REGISTER ( &sk_zombie_health3 );// {"sk_zombie_health3","0"}; - - CVAR_REGISTER ( &sk_zombie_dmg_one_slash1 );// {"sk_zombie_dmg_one_slash1","0"}; - CVAR_REGISTER ( &sk_zombie_dmg_one_slash2 );// {"sk_zombie_dmg_one_slash2","0"}; - CVAR_REGISTER ( &sk_zombie_dmg_one_slash3 );// {"sk_zombie_dmg_one_slash3","0"}; - - CVAR_REGISTER ( &sk_zombie_dmg_both_slash1 );// {"sk_zombie_dmg_both_slash1","0"}; - CVAR_REGISTER ( &sk_zombie_dmg_both_slash2 );// {"sk_zombie_dmg_both_slash2","0"}; - CVAR_REGISTER ( &sk_zombie_dmg_both_slash3 );// {"sk_zombie_dmg_both_slash3","0"}; - - - //Turret - CVAR_REGISTER ( &sk_turret_health1 );// {"sk_turret_health1","0"}; - CVAR_REGISTER ( &sk_turret_health2 );// {"sk_turret_health2","0"}; - CVAR_REGISTER ( &sk_turret_health3 );// {"sk_turret_health3","0"}; - - - // MiniTurret - CVAR_REGISTER ( &sk_miniturret_health1 );// {"sk_miniturret_health1","0"}; - CVAR_REGISTER ( &sk_miniturret_health2 );// {"sk_miniturret_health2","0"}; - CVAR_REGISTER ( &sk_miniturret_health3 );// {"sk_miniturret_health3","0"}; - - - // Sentry Turret - CVAR_REGISTER ( &sk_sentry_health1 );// {"sk_sentry_health1","0"}; - CVAR_REGISTER ( &sk_sentry_health2 );// {"sk_sentry_health2","0"}; - CVAR_REGISTER ( &sk_sentry_health3 );// {"sk_sentry_health3","0"}; - - - // PLAYER WEAPONS - - // Crowbar whack - CVAR_REGISTER ( &sk_plr_crowbar1 );// {"sk_plr_crowbar1","0"}; - CVAR_REGISTER ( &sk_plr_crowbar2 );// {"sk_plr_crowbar2","0"}; - CVAR_REGISTER ( &sk_plr_crowbar3 );// {"sk_plr_crowbar3","0"}; - - // Glock Round - CVAR_REGISTER ( &sk_plr_9mm_bullet1 );// {"sk_plr_9mm_bullet1","0"}; - CVAR_REGISTER ( &sk_plr_9mm_bullet2 );// {"sk_plr_9mm_bullet2","0"}; - CVAR_REGISTER ( &sk_plr_9mm_bullet3 );// {"sk_plr_9mm_bullet3","0"}; - - // 357 Round - CVAR_REGISTER ( &sk_plr_357_bullet1 );// {"sk_plr_357_bullet1","0"}; - CVAR_REGISTER ( &sk_plr_357_bullet2 );// {"sk_plr_357_bullet2","0"}; - CVAR_REGISTER ( &sk_plr_357_bullet3 );// {"sk_plr_357_bullet3","0"}; - - // MP5 Round - CVAR_REGISTER ( &sk_plr_9mmAR_bullet1 );// {"sk_plr_9mmAR_bullet1","0"}; - CVAR_REGISTER ( &sk_plr_9mmAR_bullet2 );// {"sk_plr_9mmAR_bullet2","0"}; - CVAR_REGISTER ( &sk_plr_9mmAR_bullet3 );// {"sk_plr_9mmAR_bullet3","0"}; - - - // M203 grenade - CVAR_REGISTER ( &sk_plr_9mmAR_grenade1 );// {"sk_plr_9mmAR_grenade1","0"}; - CVAR_REGISTER ( &sk_plr_9mmAR_grenade2 );// {"sk_plr_9mmAR_grenade2","0"}; - CVAR_REGISTER ( &sk_plr_9mmAR_grenade3 );// {"sk_plr_9mmAR_grenade3","0"}; - - - // Shotgun buckshot - CVAR_REGISTER ( &sk_plr_buckshot1 );// {"sk_plr_buckshot1","0"}; - CVAR_REGISTER ( &sk_plr_buckshot2 );// {"sk_plr_buckshot2","0"}; - CVAR_REGISTER ( &sk_plr_buckshot3 );// {"sk_plr_buckshot3","0"}; - - - // Crossbow - CVAR_REGISTER ( &sk_plr_xbow_bolt_monster1 );// {"sk_plr_xbow_bolt1","0"}; - CVAR_REGISTER ( &sk_plr_xbow_bolt_monster2 );// {"sk_plr_xbow_bolt2","0"}; - CVAR_REGISTER ( &sk_plr_xbow_bolt_monster3 );// {"sk_plr_xbow_bolt3","0"}; - - CVAR_REGISTER ( &sk_plr_xbow_bolt_client1 );// {"sk_plr_xbow_bolt1","0"}; - CVAR_REGISTER ( &sk_plr_xbow_bolt_client2 );// {"sk_plr_xbow_bolt2","0"}; - CVAR_REGISTER ( &sk_plr_xbow_bolt_client3 );// {"sk_plr_xbow_bolt3","0"}; - - - // RPG - CVAR_REGISTER ( &sk_plr_rpg1 );// {"sk_plr_rpg1","0"}; - CVAR_REGISTER ( &sk_plr_rpg2 );// {"sk_plr_rpg2","0"}; - CVAR_REGISTER ( &sk_plr_rpg3 );// {"sk_plr_rpg3","0"}; - - - // Gauss Gun - CVAR_REGISTER ( &sk_plr_gauss1 );// {"sk_plr_gauss1","0"}; - CVAR_REGISTER ( &sk_plr_gauss2 );// {"sk_plr_gauss2","0"}; - CVAR_REGISTER ( &sk_plr_gauss3 );// {"sk_plr_gauss3","0"}; - - - // Egon Gun - CVAR_REGISTER ( &sk_plr_egon_narrow1 );// {"sk_plr_egon_narrow1","0"}; - CVAR_REGISTER ( &sk_plr_egon_narrow2 );// {"sk_plr_egon_narrow2","0"}; - CVAR_REGISTER ( &sk_plr_egon_narrow3 );// {"sk_plr_egon_narrow3","0"}; - - CVAR_REGISTER ( &sk_plr_egon_wide1 );// {"sk_plr_egon_wide1","0"}; - CVAR_REGISTER ( &sk_plr_egon_wide2 );// {"sk_plr_egon_wide2","0"}; - CVAR_REGISTER ( &sk_plr_egon_wide3 );// {"sk_plr_egon_wide3","0"}; - - - // Hand Grendade - CVAR_REGISTER ( &sk_plr_hand_grenade1 );// {"sk_plr_hand_grenade1","0"}; - CVAR_REGISTER ( &sk_plr_hand_grenade2 );// {"sk_plr_hand_grenade2","0"}; - CVAR_REGISTER ( &sk_plr_hand_grenade3 );// {"sk_plr_hand_grenade3","0"}; - - - // Satchel Charge - CVAR_REGISTER ( &sk_plr_satchel1 );// {"sk_plr_satchel1","0"}; - CVAR_REGISTER ( &sk_plr_satchel2 );// {"sk_plr_satchel2","0"}; - CVAR_REGISTER ( &sk_plr_satchel3 );// {"sk_plr_satchel3","0"}; - - - // Tripmine - CVAR_REGISTER ( &sk_plr_tripmine1 );// {"sk_plr_tripmine1","0"}; - CVAR_REGISTER ( &sk_plr_tripmine2 );// {"sk_plr_tripmine2","0"}; - CVAR_REGISTER ( &sk_plr_tripmine3 );// {"sk_plr_tripmine3","0"}; - - - // WORLD WEAPONS - CVAR_REGISTER ( &sk_12mm_bullet1 );// {"sk_12mm_bullet1","0"}; - CVAR_REGISTER ( &sk_12mm_bullet2 );// {"sk_12mm_bullet2","0"}; - CVAR_REGISTER ( &sk_12mm_bullet3 );// {"sk_12mm_bullet3","0"}; - - CVAR_REGISTER ( &sk_9mmAR_bullet1 );// {"sk_9mm_bullet1","0"}; - CVAR_REGISTER ( &sk_9mmAR_bullet2 );// {"sk_9mm_bullet1","0"}; - CVAR_REGISTER ( &sk_9mmAR_bullet3 );// {"sk_9mm_bullet1","0"}; - - CVAR_REGISTER ( &sk_9mm_bullet1 );// {"sk_9mm_bullet1","0"}; - CVAR_REGISTER ( &sk_9mm_bullet2 );// {"sk_9mm_bullet2","0"}; - CVAR_REGISTER ( &sk_9mm_bullet3 );// {"sk_9mm_bullet3","0"}; - - - // HORNET - CVAR_REGISTER ( &sk_hornet_dmg1 );// {"sk_hornet_dmg1","0"}; - CVAR_REGISTER ( &sk_hornet_dmg2 );// {"sk_hornet_dmg2","0"}; - CVAR_REGISTER ( &sk_hornet_dmg3 );// {"sk_hornet_dmg3","0"}; - - // HEALTH/SUIT CHARGE DISTRIBUTION - CVAR_REGISTER ( &sk_suitcharger1 ); - CVAR_REGISTER ( &sk_suitcharger2 ); - CVAR_REGISTER ( &sk_suitcharger3 ); - - CVAR_REGISTER ( &sk_battery1 ); - CVAR_REGISTER ( &sk_battery2 ); - CVAR_REGISTER ( &sk_battery3 ); - - CVAR_REGISTER ( &sk_healthcharger1 ); - CVAR_REGISTER ( &sk_healthcharger2 ); - CVAR_REGISTER ( &sk_healthcharger3 ); - - CVAR_REGISTER ( &sk_healthkit1 ); - CVAR_REGISTER ( &sk_healthkit2 ); - CVAR_REGISTER ( &sk_healthkit3 ); - - CVAR_REGISTER ( &sk_scientist_heal1 ); - CVAR_REGISTER ( &sk_scientist_heal2 ); - CVAR_REGISTER ( &sk_scientist_heal3 ); - -// monster damage adjusters - CVAR_REGISTER ( &sk_monster_head1 ); - CVAR_REGISTER ( &sk_monster_head2 ); - CVAR_REGISTER ( &sk_monster_head3 ); - - CVAR_REGISTER ( &sk_monster_chest1 ); - CVAR_REGISTER ( &sk_monster_chest2 ); - CVAR_REGISTER ( &sk_monster_chest3 ); - - CVAR_REGISTER ( &sk_monster_stomach1 ); - CVAR_REGISTER ( &sk_monster_stomach2 ); - CVAR_REGISTER ( &sk_monster_stomach3 ); - - CVAR_REGISTER ( &sk_monster_arm1 ); - CVAR_REGISTER ( &sk_monster_arm2 ); - CVAR_REGISTER ( &sk_monster_arm3 ); - - CVAR_REGISTER ( &sk_monster_leg1 ); - CVAR_REGISTER ( &sk_monster_leg2 ); - CVAR_REGISTER ( &sk_monster_leg3 ); - -// player damage adjusters - CVAR_REGISTER ( &sk_player_head1 ); - CVAR_REGISTER ( &sk_player_head2 ); - CVAR_REGISTER ( &sk_player_head3 ); - - CVAR_REGISTER ( &sk_player_chest1 ); - CVAR_REGISTER ( &sk_player_chest2 ); - CVAR_REGISTER ( &sk_player_chest3 ); - - CVAR_REGISTER ( &sk_player_stomach1 ); - CVAR_REGISTER ( &sk_player_stomach2 ); - CVAR_REGISTER ( &sk_player_stomach3 ); - - CVAR_REGISTER ( &sk_player_arm1 ); - CVAR_REGISTER ( &sk_player_arm2 ); - CVAR_REGISTER ( &sk_player_arm3 ); - - CVAR_REGISTER ( &sk_player_leg1 ); - CVAR_REGISTER ( &sk_player_leg2 ); - CVAR_REGISTER ( &sk_player_leg3 ); -// END REGISTER CVARS FOR SKILL LEVEL STUFF - - SERVER_COMMAND( "exec skill.cfg\n" ); -} - diff --git a/sdk/dlls/game.h b/sdk/dlls/game.h deleted file mode 100644 index 58e7e75..0000000 --- a/sdk/dlls/game.h +++ /dev/null @@ -1,45 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef GAME_H -#define GAME_H - -extern void GameDLLInit( void ); - - -extern cvar_t displaysoundlist; - -// multiplayer server rules -extern cvar_t teamplay; -extern cvar_t fraglimit; -extern cvar_t timelimit; -extern cvar_t friendlyfire; -extern cvar_t falldamage; -extern cvar_t weaponstay; -extern cvar_t forcerespawn; -extern cvar_t flashlight; -extern cvar_t aimcrosshair; -extern cvar_t decalfrequency; -extern cvar_t teamlist; -extern cvar_t teamoverride; -extern cvar_t defaultteam; -extern cvar_t allowmonsters; - -// Engine Cvars -extern cvar_t *g_psv_gravity; -extern cvar_t *g_psv_aim; -extern cvar_t *g_footsteps; - -#endif // GAME_H diff --git a/sdk/dlls/gamerules.cpp b/sdk/dlls/gamerules.cpp deleted file mode 100644 index 829cae0..0000000 --- a/sdk/dlls/gamerules.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// GameRules.cpp -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "skill.h" -#include "game.h" - -extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - -DLL_GLOBAL CGameRules* g_pGameRules = NULL; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int gmsgDeathMsg; // client dll messages -extern int gmsgMOTD; - -int g_teamplay = 0; - -//========================================================= -//========================================================= -BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry ) -{ - int iAmmoIndex; - - if ( pszAmmoName ) - { - iAmmoIndex = pPlayer->GetAmmoIndex( pszAmmoName ); - - if ( iAmmoIndex > -1 ) - { - if ( pPlayer->AmmoInventory( iAmmoIndex ) < iMaxCarry ) - { - // player has room for more of this type of ammo - return TRUE; - } - } - } - - return FALSE; -} - -//========================================================= -//========================================================= -edict_t *CGameRules :: GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); - - pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); - pPlayer->pev->v_angle = g_vecZero; - pPlayer->pev->velocity = g_vecZero; - pPlayer->pev->angles = VARS(pentSpawnSpot)->angles; - pPlayer->pev->punchangle = g_vecZero; - pPlayer->pev->fixangle = TRUE; - - return pentSpawnSpot; -} - -//========================================================= -//========================================================= -BOOL CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - // only living players can have items - if ( pPlayer->pev->deadflag != DEAD_NO ) - return FALSE; - - if ( pWeapon->pszAmmo1() ) - { - if ( !CanHaveAmmo( pPlayer, pWeapon->pszAmmo1(), pWeapon->iMaxAmmo1() ) ) - { - // we can't carry anymore ammo for this gun. We can only - // have the gun if we aren't already carrying one of this type - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - } - else - { - // weapon doesn't use ammo, don't take another if you already have it. - if ( pPlayer->HasPlayerItem( pWeapon ) ) - { - return FALSE; - } - } - - // note: will fall through to here if GetItemInfo doesn't fill the struct! - return TRUE; -} - -//========================================================= -// load the SkillData struct with the proper values based on the skill level. -//========================================================= -void CGameRules::RefreshSkillData ( void ) -{ - int iSkill; - - iSkill = (int)CVAR_GET_FLOAT("skill"); - g_iSkillLevel = iSkill; - - if ( iSkill < 1 ) - { - iSkill = 1; - } - else if ( iSkill > 3 ) - { - iSkill = 3; - } - - gSkillData.iSkillLevel = iSkill; - - ALERT ( at_console, "\nGAME SKILL LEVEL:%d\n",iSkill ); - - //Agrunt - gSkillData.agruntHealth = GetSkillCvar( "sk_agrunt_health" ); - gSkillData.agruntDmgPunch = GetSkillCvar( "sk_agrunt_dmg_punch"); - - // Apache - gSkillData.apacheHealth = GetSkillCvar( "sk_apache_health"); - - // Barney - gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health"); - - // Big Momma - gSkillData.bigmommaHealthFactor = GetSkillCvar( "sk_bigmomma_health_factor" ); - gSkillData.bigmommaDmgSlash = GetSkillCvar( "sk_bigmomma_dmg_slash" ); - gSkillData.bigmommaDmgBlast = GetSkillCvar( "sk_bigmomma_dmg_blast" ); - gSkillData.bigmommaRadiusBlast = GetSkillCvar( "sk_bigmomma_radius_blast" ); - - // Bullsquid - gSkillData.bullsquidHealth = GetSkillCvar( "sk_bullsquid_health"); - gSkillData.bullsquidDmgBite = GetSkillCvar( "sk_bullsquid_dmg_bite"); - gSkillData.bullsquidDmgWhip = GetSkillCvar( "sk_bullsquid_dmg_whip"); - gSkillData.bullsquidDmgSpit = GetSkillCvar( "sk_bullsquid_dmg_spit"); - - // Gargantua - gSkillData.gargantuaHealth = GetSkillCvar( "sk_gargantua_health"); - gSkillData.gargantuaDmgSlash = GetSkillCvar( "sk_gargantua_dmg_slash"); - gSkillData.gargantuaDmgFire = GetSkillCvar( "sk_gargantua_dmg_fire"); - gSkillData.gargantuaDmgStomp = GetSkillCvar( "sk_gargantua_dmg_stomp"); - - // Hassassin - gSkillData.hassassinHealth = GetSkillCvar( "sk_hassassin_health"); - - // Headcrab - gSkillData.headcrabHealth = GetSkillCvar( "sk_headcrab_health"); - gSkillData.headcrabDmgBite = GetSkillCvar( "sk_headcrab_dmg_bite"); - - // Hgrunt - gSkillData.hgruntHealth = GetSkillCvar( "sk_hgrunt_health"); - gSkillData.hgruntDmgKick = GetSkillCvar( "sk_hgrunt_kick"); - gSkillData.hgruntShotgunPellets = GetSkillCvar( "sk_hgrunt_pellets"); - gSkillData.hgruntGrenadeSpeed = GetSkillCvar( "sk_hgrunt_gspeed"); - - // Houndeye - gSkillData.houndeyeHealth = GetSkillCvar( "sk_houndeye_health"); - gSkillData.houndeyeDmgBlast = GetSkillCvar( "sk_houndeye_dmg_blast"); - - // ISlave - gSkillData.slaveHealth = GetSkillCvar( "sk_islave_health"); - gSkillData.slaveDmgClaw = GetSkillCvar( "sk_islave_dmg_claw"); - gSkillData.slaveDmgClawrake = GetSkillCvar( "sk_islave_dmg_clawrake"); - gSkillData.slaveDmgZap = GetSkillCvar( "sk_islave_dmg_zap"); - - // Icthyosaur - gSkillData.ichthyosaurHealth = GetSkillCvar( "sk_ichthyosaur_health"); - gSkillData.ichthyosaurDmgShake = GetSkillCvar( "sk_ichthyosaur_shake"); - - // Leech - gSkillData.leechHealth = GetSkillCvar( "sk_leech_health"); - - gSkillData.leechDmgBite = GetSkillCvar( "sk_leech_dmg_bite"); - - // Controller - gSkillData.controllerHealth = GetSkillCvar( "sk_controller_health"); - gSkillData.controllerDmgZap = GetSkillCvar( "sk_controller_dmgzap"); - gSkillData.controllerSpeedBall = GetSkillCvar( "sk_controller_speedball"); - gSkillData.controllerDmgBall = GetSkillCvar( "sk_controller_dmgball"); - - // Nihilanth - gSkillData.nihilanthHealth = GetSkillCvar( "sk_nihilanth_health"); - gSkillData.nihilanthZap = GetSkillCvar( "sk_nihilanth_zap"); - - // Scientist - gSkillData.scientistHealth = GetSkillCvar( "sk_scientist_health"); - - // Snark - gSkillData.snarkHealth = GetSkillCvar( "sk_snark_health"); - gSkillData.snarkDmgBite = GetSkillCvar( "sk_snark_dmg_bite"); - gSkillData.snarkDmgPop = GetSkillCvar( "sk_snark_dmg_pop"); - - // Zombie - gSkillData.zombieHealth = GetSkillCvar( "sk_zombie_health"); - gSkillData.zombieDmgOneSlash = GetSkillCvar( "sk_zombie_dmg_one_slash"); - gSkillData.zombieDmgBothSlash = GetSkillCvar( "sk_zombie_dmg_both_slash"); - - //Turret - gSkillData.turretHealth = GetSkillCvar( "sk_turret_health"); - - // MiniTurret - gSkillData.miniturretHealth = GetSkillCvar( "sk_miniturret_health"); - - // Sentry Turret - gSkillData.sentryHealth = GetSkillCvar( "sk_sentry_health"); - -// PLAYER WEAPONS - - // Crowbar whack - gSkillData.plrDmgCrowbar = GetSkillCvar( "sk_plr_crowbar"); - - // Glock Round - gSkillData.plrDmg9MM = GetSkillCvar( "sk_plr_9mm_bullet"); - - // 357 Round - gSkillData.plrDmg357 = GetSkillCvar( "sk_plr_357_bullet"); - - // MP5 Round - gSkillData.plrDmgMP5 = GetSkillCvar( "sk_plr_9mmAR_bullet"); - - // M203 grenade - gSkillData.plrDmgM203Grenade = GetSkillCvar( "sk_plr_9mmAR_grenade"); - - // Shotgun buckshot - gSkillData.plrDmgBuckshot = GetSkillCvar( "sk_plr_buckshot"); - - // Crossbow - gSkillData.plrDmgCrossbowClient = GetSkillCvar( "sk_plr_xbow_bolt_client"); - gSkillData.plrDmgCrossbowMonster = GetSkillCvar( "sk_plr_xbow_bolt_monster"); - - // RPG - gSkillData.plrDmgRPG = GetSkillCvar( "sk_plr_rpg"); - - // Gauss gun - gSkillData.plrDmgGauss = GetSkillCvar( "sk_plr_gauss"); - - // Egon Gun - gSkillData.plrDmgEgonNarrow = GetSkillCvar( "sk_plr_egon_narrow"); - gSkillData.plrDmgEgonWide = GetSkillCvar( "sk_plr_egon_wide"); - - // Hand Grendade - gSkillData.plrDmgHandGrenade = GetSkillCvar( "sk_plr_hand_grenade"); - - // Satchel Charge - gSkillData.plrDmgSatchel = GetSkillCvar( "sk_plr_satchel"); - - // Tripmine - gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine"); - - // MONSTER WEAPONS - gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet"); - gSkillData.monDmgMP5 = GetSkillCvar ("sk_9mmAR_bullet" ); - gSkillData.monDmg9MM = GetSkillCvar( "sk_9mm_bullet"); - - // MONSTER HORNET - gSkillData.monDmgHornet = GetSkillCvar( "sk_hornet_dmg"); - - // PLAYER HORNET -// Up to this point, player hornet damage and monster hornet damage were both using -// monDmgHornet to determine how much damage to do. In tuning the hivehand, we now need -// to separate player damage and monster hivehand damage. Since it's so late in the project, we've -// added plrDmgHornet to the SKILLDATA struct, but not to the engine CVar list, so it's inaccesible -// via SKILLS.CFG. Any player hivehand tuning must take place in the code. (sjb) - gSkillData.plrDmgHornet = 7; - - - // HEALTH/CHARGE - gSkillData.suitchargerCapacity = GetSkillCvar( "sk_suitcharger" ); - gSkillData.batteryCapacity = GetSkillCvar( "sk_battery" ); - gSkillData.healthchargerCapacity = GetSkillCvar ( "sk_healthcharger" ); - gSkillData.healthkitCapacity = GetSkillCvar ( "sk_healthkit" ); - gSkillData.scientistHeal = GetSkillCvar ( "sk_scientist_heal" ); - - // monster damage adj - gSkillData.monHead = GetSkillCvar( "sk_monster_head" ); - gSkillData.monChest = GetSkillCvar( "sk_monster_chest" ); - gSkillData.monStomach = GetSkillCvar( "sk_monster_stomach" ); - gSkillData.monLeg = GetSkillCvar( "sk_monster_leg" ); - gSkillData.monArm = GetSkillCvar( "sk_monster_arm" ); - - // player damage adj - gSkillData.plrHead = GetSkillCvar( "sk_player_head" ); - gSkillData.plrChest = GetSkillCvar( "sk_player_chest" ); - gSkillData.plrStomach = GetSkillCvar( "sk_player_stomach" ); - gSkillData.plrLeg = GetSkillCvar( "sk_player_leg" ); - gSkillData.plrArm = GetSkillCvar( "sk_player_arm" ); -} - -//========================================================= -// instantiate the proper game rules object -//========================================================= - -CGameRules *InstallGameRules( void ) -{ - SERVER_COMMAND( "exec game.cfg\n" ); - SERVER_EXECUTE( ); - - if ( !gpGlobals->deathmatch ) - { - // generic half-life - g_teamplay = 0; - return new CHalfLifeRules; - } - else - { - if ( teamplay.value > 0 ) - { - // teamplay - - g_teamplay = 1; - return new CHalfLifeTeamplay; - } - if ((int)gpGlobals->deathmatch == 1) - { - // vanilla deathmatch - g_teamplay = 0; - return new CHalfLifeMultiplay; - } - else - { - // vanilla deathmatch?? - g_teamplay = 0; - return new CHalfLifeMultiplay; - } - } -} - - - diff --git a/sdk/dlls/gamerules.h b/sdk/dlls/gamerules.h deleted file mode 100644 index 76b3515..0000000 --- a/sdk/dlls/gamerules.h +++ /dev/null @@ -1,360 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// GameRules -//========================================================= - -//#include "weapons.h" -//#include "items.h" -class CBasePlayerItem; -class CBasePlayer; -class CItem; -class CBasePlayerAmmo; - -// weapon respawning return codes -enum -{ - GR_NONE = 0, - - GR_WEAPON_RESPAWN_YES, - GR_WEAPON_RESPAWN_NO, - - GR_AMMO_RESPAWN_YES, - GR_AMMO_RESPAWN_NO, - - GR_ITEM_RESPAWN_YES, - GR_ITEM_RESPAWN_NO, - - GR_PLR_DROP_GUN_ALL, - GR_PLR_DROP_GUN_ACTIVE, - GR_PLR_DROP_GUN_NO, - - GR_PLR_DROP_AMMO_ALL, - GR_PLR_DROP_AMMO_ACTIVE, - GR_PLR_DROP_AMMO_NO, -}; - -// Player relationship return codes -enum -{ - GR_NOTTEAMMATE = 0, - GR_TEAMMATE, - GR_ENEMY, - GR_ALLY, - GR_NEUTRAL, -}; - -class CGameRules -{ -public: - virtual void RefreshSkillData( void );// fill skill data struct with proper values - virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). - - virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// should the player switch to this weapon? - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one. - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) - virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game? - virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? - virtual BOOL IsCoOp( void ) = 0;// is this a coop game? - virtual const char *GetGameDescription( void ) { return "Half-Life"; } // this is the game name that gets seen in the server browser - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) = 0;// a client just connected to the server (player hasn't spawned yet) - virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server - virtual void UpdateGameMode( CBasePlayer *pPlayer ) {} // the client needs to be informed of the current game mode - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game - virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. - - virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; }; - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary. -// Weapon retrieval - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ) = 0;// should this weapon respawn? - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) = 0;// when may this weapon respawn? - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) = 0;// where in the world should this weapon respawn? - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit, longjump) - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? - virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? - virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? - -// Ammo retrieval - virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo? - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) = 0;// should this ammo item respawn? - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) = 0;// when should this ammo item respawn? - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) = 0;// where in the world should this ammo item respawn? - // by default, everything spawns - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? - virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? - virtual int GetTeamIndex( const char *pTeamName ) { return -1; } - virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } - virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; } - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} - virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } - -// Sounds - virtual BOOL PlayTextureSounds( void ) { return TRUE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } - -// Monsters - virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) {} -}; - -extern CGameRules *InstallGameRules( void ); - - -//========================================================= -// CHalfLifeRules - rules for the single player Half-Life -// game. -//========================================================= -class CHalfLifeRules : public CGameRules -{ -public: - CHalfLifeRules ( void ); - -// GR_Think - virtual void Think( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ) { return TRUE; }; - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ); - virtual float FlItemRespawnTime( CItem *pItem ); - virtual Vector VecItemRespawnSpot( CItem *pItem ); - -// Ammo retrieval - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); -}; - -//========================================================= -// CHalfLifeMultiplay - rules for the basic half life multiplayer -// competition -//========================================================= -class CHalfLifeMultiplay : public CGameRules -{ -public: - CHalfLifeMultiplay(); - -// GR_Think - virtual void Think( void ); - virtual void RefreshSkillData( void ); - virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); - virtual BOOL FAllowFlashlight( void ); - - virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// Functions to verify the single/multiplayer status of a game - virtual BOOL IsMultiplayer( void ); - virtual BOOL IsDeathmatch( void ); - virtual BOOL IsCoOp( void ); - -// Client connection/disconnection - // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in - // svRejectReason - // Only the client's name and remote address are provided to the dll for verification. - virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); - virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating - virtual void ClientDisconnected( edict_t *pClient ); - virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode - -// Client damage rules - virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - -// Client spawn/respawn control - virtual void PlayerSpawn( CBasePlayer *pPlayer ); - virtual void PlayerThink( CBasePlayer *pPlayer ); - virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); - virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); - virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); - - virtual BOOL AllowAutoTargetCrosshair( void ); - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - -// Client kills/scoring - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - -// Weapon retrieval - virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); - virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? - -// Weapon spawn/respawn control - virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); - virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); - virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); - virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); - -// Item retrieval - virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); - virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); - -// Item spawn/respawn control - virtual int ItemShouldRespawn( CItem *pItem ); - virtual float FlItemRespawnTime( CItem *pItem ); - virtual Vector VecItemRespawnSpot( CItem *pItem ); - -// Ammo retrieval - virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); - -// Ammo spawn/respawn control - virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); - virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); - virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); - -// Healthcharger respawn control - virtual float FlHealthChargerRechargeTime( void ); - virtual float FlHEVChargerRechargeTime( void ); - -// What happens to a dead player's weapons - virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); - -// What happens to a dead player's ammo - virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); - -// Teamplay stuff - virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - - virtual BOOL PlayTextureSounds( void ) { return FALSE; } - virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); - -// Monsters - virtual BOOL FAllowMonsters( void ); - - // Immediately end a multiplayer game - virtual void EndMultiplayerGame( void ) { GoToIntermission(); } - -protected: - virtual void ChangeLevel( void ); - virtual void GoToIntermission( void ); - float m_flIntermissionEndTime; - BOOL m_iEndIntermissionButtonHit; - void SendMOTDToClient( edict_t *client ); -}; - -extern DLL_GLOBAL CGameRules* g_pGameRules; diff --git a/sdk/dlls/gargantua.cpp b/sdk/dlls/gargantua.cpp deleted file mode 100644 index faf9964..0000000 --- a/sdk/dlls/gargantua.cpp +++ /dev/null @@ -1,1367 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef OEM_BUILD - -//========================================================= -// Gargantua -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "schedule.h" -#include "customentity.h" -#include "weapons.h" -#include "effects.h" -#include "soundent.h" -#include "decals.h" -#include "explode.h" -#include "func_break.h" - -//========================================================= -// Gargantua Monster -//========================================================= -const float GARG_ATTACKDIST = 80.0; - -// Garg animation events -#define GARG_AE_SLASH_LEFT 1 -//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used -#define GARG_AE_LEFT_FOOT 3 -#define GARG_AE_RIGHT_FOOT 4 -#define GARG_AE_STOMP 5 -#define GARG_AE_BREATHE 6 - - -// Gargantua is immune to any damage but this -#define GARG_DAMAGE (DMG_ENERGYBEAM|DMG_CRUSH|DMG_MORTAR|DMG_BLAST) -#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr" -#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr" -#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr" -#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav" -#define GARG_FLAME_LENGTH 330 -#define GARG_GIB_MODEL "models/metalplategibs.mdl" - -#define ATTN_GARG (ATTN_NORM) - -#define STOMP_SPRITE_COUNT 10 - -int gStompSprite = 0, gGargGibModel = 0; -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ); - -class CSmoker; - -// Spiral Effect -class CSpiral : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - static CSpiral *Create( const Vector &origin, float height, float radius, float duration ); -}; -LINK_ENTITY_TO_CLASS( streak_spiral, CSpiral ); - - -class CStomp : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - static CStomp *StompCreate( const Vector &origin, const Vector &end, float speed ); - -private: -// UNDONE: re-use this sprite list instead of creating new ones all the time -// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ]; -}; - -LINK_ENTITY_TO_CLASS( garg_stomp, CStomp ); -CStomp *CStomp::StompCreate( const Vector &origin, const Vector &end, float speed ) -{ - CStomp *pStomp = GetClassPtr( (CStomp *)NULL ); - - pStomp->pev->origin = origin; - Vector dir = (end - origin); - pStomp->pev->scale = dir.Length(); - pStomp->pev->movedir = dir.Normalize(); - pStomp->pev->speed = speed; - pStomp->Spawn(); - - return pStomp; -} - -void CStomp::Spawn( void ) -{ - pev->nextthink = gpGlobals->time; - pev->classname = MAKE_STRING("garg_stomp"); - pev->dmgtime = gpGlobals->time; - - pev->framerate = 30; - pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - EMIT_SOUND_DYN( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55); -} - - -#define STOMP_INTERVAL 0.025 - -void CStomp::Think( void ) -{ - TraceResult tr; - - pev->nextthink = gpGlobals->time + 0.1; - - // Do damage for this frame - Vector vecStart = pev->origin; - vecStart.z += 30; - Vector vecEnd = vecStart + (pev->movedir * pev->speed * gpGlobals->frametime); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit && tr.pHit != pev->owner ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - entvars_t *pevOwner = pev; - if ( pev->owner ) - pevOwner = VARS(pev->owner); - - if ( pEntity ) - pEntity->TakeDamage( pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC ); - } - - // Accelerate the effect - pev->speed = pev->speed + (gpGlobals->frametime) * pev->framerate; - pev->framerate = pev->framerate + (gpGlobals->frametime) * 1500; - - // Move and spawn trails - while ( gpGlobals->time - pev->dmgtime > STOMP_INTERVAL ) - { - pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL; - for ( int i = 0; i < 2; i++ ) - { - CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, pev->origin, TRUE ); - if ( pSprite ) - { - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,500), ignore_monsters, edict(), &tr ); - pSprite->pev->origin = tr.vecEndPos; - pSprite->pev->velocity = Vector(RANDOM_FLOAT(-200,200),RANDOM_FLOAT(-200,200),175); - // pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) ); - pSprite->pev->nextthink = gpGlobals->time + 0.3; - pSprite->SetThink( &CSprite::SUB_Remove ); - pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); - } - } - pev->dmgtime += STOMP_INTERVAL; - // Scale has the "life" of this effect - pev->scale -= STOMP_INTERVAL * pev->speed; - if ( pev->scale <= 0 ) - { - // Life has run out - UTIL_Remove(this); - STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); - } - - } -} - - -void StreakSplash( const Vector &origin, const Vector &direction, int color, int count, int speed, int velocityRange ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_STREAK_SPLASH ); - WRITE_COORD( origin.x ); // origin - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); // direction - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); // Streak color 6 - WRITE_SHORT( count ); // count - WRITE_SHORT( speed ); - WRITE_SHORT( velocityRange ); // Random velocity modifier - MESSAGE_END(); -} - - -class CGargantua : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - BOOL CheckMeleeAttack1( float flDot, float flDist ); // Swipe - BOOL CheckMeleeAttack2( float flDot, float flDist ); // Flames - BOOL CheckRangeAttack1( float flDot, float flDist ); // Stomp attack - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -80, -80, 0 ); - pev->absmax = pev->origin + Vector( 80, 80, 214 ); - } - - Schedule_t *GetScheduleOfType( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - void PrescheduleThink( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void DeathEffect( void ); - - void EyeOff( void ); - void EyeOn( int level ); - void EyeUpdate( void ); - void Leap( void ); - void StompAttack( void ); - void FlameCreate( void ); - void FlameUpdate( void ); - void FlameControls( float angleX, float angleY ); - void FlameDestroy( void ); - inline BOOL FlameIsOn( void ) { return m_pFlame[0] != NULL; } - - void FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES; - -private: - static const char *pAttackHitSounds[]; - static const char *pBeamAttackSounds[]; - static const char *pAttackMissSounds[]; - static const char *pRicSounds[]; - static const char *pFootSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pStompSounds[]; - static const char *pBreatheSounds[]; - - CBaseEntity* GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType); - - CSprite *m_pEyeGlow; // Glow around the eyes - CBeam *m_pFlame[4]; // Flame beams - - int m_eyeBrightness; // Brightness target - float m_seeTime; // Time to attack (when I see the enemy, I set this) - float m_flameTime; // Time of next flame attack - float m_painSoundTime; // Time of next pain sound - float m_streakTime; // streak timer (don't send too many) - float m_flameX; // Flame thrower aim - float m_flameY; -}; - -LINK_ENTITY_TO_CLASS( monster_gargantua, CGargantua ); - -TYPEDESCRIPTION CGargantua::m_SaveData[] = -{ - DEFINE_FIELD( CGargantua, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CGargantua, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CGargantua, m_seeTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_flameTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_streakTime, FIELD_TIME ), - DEFINE_FIELD( CGargantua, m_painSoundTime, FIELD_TIME ), - DEFINE_ARRAY( CGargantua, m_pFlame, FIELD_CLASSPTR, 4 ), - DEFINE_FIELD( CGargantua, m_flameX, FIELD_FLOAT ), - DEFINE_FIELD( CGargantua, m_flameY, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CGargantua, CBaseMonster ); - -const char *CGargantua::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CGargantua::pBeamAttackSounds[] = -{ - "garg/gar_flameoff1.wav", - "garg/gar_flameon1.wav", - "garg/gar_flamerun1.wav", -}; - - -const char *CGargantua::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CGargantua::pRicSounds[] = -{ -#if 0 - "weapons/ric1.wav", - "weapons/ric2.wav", - "weapons/ric3.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#else - "debris/metal4.wav", - "debris/metal6.wav", - "weapons/ric4.wav", - "weapons/ric5.wav", -#endif -}; - -const char *CGargantua::pFootSounds[] = -{ - "garg/gar_step1.wav", - "garg/gar_step2.wav", -}; - - -const char *CGargantua::pIdleSounds[] = -{ - "garg/gar_idle1.wav", - "garg/gar_idle2.wav", - "garg/gar_idle3.wav", - "garg/gar_idle4.wav", - "garg/gar_idle5.wav", -}; - - -const char *CGargantua::pAttackSounds[] = -{ - "garg/gar_attack1.wav", - "garg/gar_attack2.wav", - "garg/gar_attack3.wav", -}; - -const char *CGargantua::pAlertSounds[] = -{ - "garg/gar_alert1.wav", - "garg/gar_alert2.wav", - "garg/gar_alert3.wav", -}; - -const char *CGargantua::pPainSounds[] = -{ - "garg/gar_pain1.wav", - "garg/gar_pain2.wav", - "garg/gar_pain3.wav", -}; - -const char *CGargantua::pStompSounds[] = -{ - "garg/gar_stomp1.wav", -}; - -const char *CGargantua::pBreatheSounds[] = -{ - "garg/gar_breathe1.wav", - "garg/gar_breathe2.wav", - "garg/gar_breathe3.wav", -}; -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -#if 0 -enum -{ - SCHED_ = LAST_COMMON_SCHEDULE + 1, -}; -#endif - -enum -{ - TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1, - TASK_FLAME_SWEEP, -}; - -Task_t tlGargFlame[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SOUND_ATTACK, (float)0 }, - // { TASK_PLAY_SEQUENCE, (float)ACT_SIGNAL1 }, - { TASK_SET_ACTIVITY, (float)ACT_MELEE_ATTACK2 }, - { TASK_FLAME_SWEEP, (float)4.5 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slGargFlame[] = -{ - { - tlGargFlame, - ARRAYSIZE ( tlGargFlame ), - 0, - 0, - "GargFlame" - }, -}; - - -// primary melee attack -Task_t tlGargSwipe[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_MELEE_ATTACK1, (float)0 }, -}; - -Schedule_t slGargSwipe[] = -{ - { - tlGargSwipe, - ARRAYSIZE ( tlGargSwipe ), - bits_COND_CAN_MELEE_ATTACK2, - 0, - "GargSwipe" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CGargantua ) -{ - slGargFlame, - slGargSwipe, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CGargantua, CBaseMonster ); - - -void CGargantua::EyeOn( int level ) -{ - m_eyeBrightness = level; -} - - -void CGargantua::EyeOff( void ) -{ - m_eyeBrightness = 0; -} - - -void CGargantua::EyeUpdate( void ) -{ - if ( m_pEyeGlow ) - { - m_pEyeGlow->pev->renderamt = UTIL_Approach( m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26 ); - if ( m_pEyeGlow->pev->renderamt == 0 ) - m_pEyeGlow->pev->effects |= EF_NODRAW; - else - m_pEyeGlow->pev->effects &= ~EF_NODRAW; - UTIL_SetOrigin( m_pEyeGlow->pev, pev->origin ); - } -} - - -void CGargantua::StompAttack( void ) -{ - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin + Vector(0,0,60) + 35 * gpGlobals->v_forward; - Vector vecAim = ShootAtEnemy( vecStart ); - Vector vecEnd = (vecAim * 1024) + vecStart; - - UTIL_TraceLine( vecStart, vecEnd, ignore_monsters, edict(), &trace ); - CStomp::StompCreate( vecStart, trace.vecEndPos, 0 ); - UTIL_ScreenShake( pev->origin, 12.0, 100.0, 2.0, 1000 ); - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pStompSounds[ RANDOM_LONG(0,ARRAYSIZE(pStompSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,20), ignore_monsters, edict(), &trace ); - if ( trace.flFraction < 1.0 ) - UTIL_DecalTrace( &trace, DECAL_GARGSTOMP1 ); -} - - -void CGargantua :: FlameCreate( void ) -{ - int i; - Vector posGun, angleGun; - TraceResult trace; - - UTIL_MakeVectors( pev->angles ); - - for ( i = 0; i < 4; i++ ) - { - if ( i < 2 ) - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE_NAME, 240 ); - else - m_pFlame[i] = CBeam::BeamCreate( GARG_BEAM_SPRITE2, 140 ); - if ( m_pFlame[i] ) - { - int attach = i%2; - // attachment is 0 based in GetAttachment - GetAttachment( attach+1, posGun, angleGun ); - - Vector vecEnd = (gpGlobals->v_forward * GARG_FLAME_LENGTH) + posGun; - UTIL_TraceLine( posGun, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->PointEntInit( trace.vecEndPos, entindex() ); - if ( i < 2 ) - m_pFlame[i]->SetColor( 255, 130, 90 ); - else - m_pFlame[i]->SetColor( 0, 120, 255 ); - m_pFlame[i]->SetBrightness( 190 ); - m_pFlame[i]->SetFlags( BEAM_FSHADEIN ); - m_pFlame[i]->SetScrollRate( 20 ); - // attachment is 1 based in SetEndAttachment - m_pFlame[i]->SetEndAttachment( attach + 2 ); - CSoundEnt::InsertSound( bits_SOUND_COMBAT, posGun, 384, 0.3 ); - } - } - EMIT_SOUND_DYN ( edict(), CHAN_BODY, pBeamAttackSounds[ 1 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 2 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); -} - - -void CGargantua :: FlameControls( float angleX, float angleY ) -{ - if ( angleY < -180 ) - angleY += 360; - else if ( angleY > 180 ) - angleY -= 360; - - if ( angleY < -45 ) - angleY = -45; - else if ( angleY > 45 ) - angleY = 45; - - m_flameX = UTIL_ApproachAngle( angleX, m_flameX, 4 ); - m_flameY = UTIL_ApproachAngle( angleY, m_flameY, 8 ); - SetBoneController( 0, m_flameY ); - SetBoneController( 1, m_flameX ); -} - - -void CGargantua :: FlameUpdate( void ) -{ - int i; - TraceResult trace; - Vector vecStart, angleGun; - BOOL streaks = FALSE; - - for ( i = 0; i < 2; i++ ) - { - if ( m_pFlame[i] ) - { - Vector vecAim = pev->angles; - vecAim.x += m_flameX; - vecAim.y += m_flameY; - - UTIL_MakeVectors( vecAim ); - - GetAttachment( i+1, vecStart, angleGun ); - Vector vecEnd = vecStart + (gpGlobals->v_forward * GARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right; - - UTIL_TraceLine( vecStart, vecEnd, dont_ignore_monsters, edict(), &trace ); - - m_pFlame[i]->SetStartPos( trace.vecEndPos ); - m_pFlame[i+2]->SetStartPos( (vecStart * 0.6) + (trace.vecEndPos * 0.4) ); - - if ( trace.flFraction != 1.0 && gpGlobals->time > m_streakTime ) - { - StreakSplash( trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400 ); - streaks = TRUE; - UTIL_DecalTrace( &trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0,2) ); - } - // RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - FlameDamage( vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 * (i + 2) ); // entity, attachment - WRITE_COORD( vecStart.x ); // origin - WRITE_COORD( vecStart.y ); - WRITE_COORD( vecStart.z ); - WRITE_COORD( RANDOM_FLOAT( 32, 48 ) ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - if ( streaks ) - m_streakTime = gpGlobals->time; -} - - - -void CGargantua :: FlameDamage( Vector vecStart, Vector vecEnd, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) -{ - CBaseEntity *pEntity = NULL; - TraceResult tr; - float flAdjustedDamage; - Vector vecSpot; - - Vector vecMid = (vecStart + vecEnd) * 0.5; - - float searchRadius = (vecStart - vecMid).Length(); - - Vector vecAim = (vecEnd - vecStart).Normalize( ); - - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecMid, searchRadius )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - // UNDONE: this should check a damage mask, not an ignore - if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) - {// houndeyes don't hurt other houndeyes with their attack - continue; - } - - vecSpot = pEntity->BodyTarget( vecMid ); - - float dist = DotProduct( vecAim, vecSpot - vecMid ); - if (dist > searchRadius) - dist = searchRadius; - else if (dist < -searchRadius) - dist = searchRadius; - - Vector vecSrc = vecMid + dist * vecAim; - - UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr ); - - if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() ) - {// the explosion can 'see' this entity, so hurt them! - // decrease damage for an ent that's farther from the flame. - dist = ( vecSrc - tr.vecEndPos ).Length(); - - if (dist > 64) - { - flAdjustedDamage = flDamage - (dist - 64) * 0.4; - if (flAdjustedDamage <= 0) - continue; - } - else - { - flAdjustedDamage = flDamage; - } - - // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) ); - if (tr.flFraction != 1.0) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType ); - ApplyMultiDamage( pevInflictor, pevAttacker ); - } - else - { - pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType ); - } - } - } - } -} - - -void CGargantua :: FlameDestroy( void ) -{ - int i; - - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pBeamAttackSounds[ 0 ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - for ( i = 0; i < 4; i++ ) - { - if ( m_pFlame[i] ) - { - UTIL_Remove( m_pFlame[i] ); - m_pFlame[i] = NULL; - } - } -} - - -void CGargantua :: PrescheduleThink( void ) -{ - if ( !HasConditions( bits_COND_SEE_ENEMY ) ) - { - m_seeTime = gpGlobals->time + 5; - EyeOff(); - } - else - EyeOn( 200 ); - - EyeUpdate(); -} - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGargantua :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGargantua :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 60; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_WALK: - case ACT_RUN: - ys = 60; - break; - - default: - ys = 60; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// Spawn -//========================================================= -void CGargantua :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/garg.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.gargantuaHealth; - //pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file - m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 1 ); - EyeOff(); - m_seeTime = gpGlobals->time + 5; - m_flameTime = gpGlobals->time + 2; -} - - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGargantua :: Precache() -{ - size_t i; - - PRECACHE_MODEL("models/garg.mdl"); - PRECACHE_MODEL( GARG_EYE_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE_NAME ); - PRECACHE_MODEL( GARG_BEAM_SPRITE2 ); - gStompSprite = PRECACHE_MODEL( GARG_STOMP_SPRITE_NAME ); - gGargGibModel = PRECACHE_MODEL( GARG_GIB_MODEL ); - PRECACHE_SOUND( GARG_STOMP_BUZZ_SOUND ); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pBeamAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pBeamAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pRicSounds ); i++ ) - PRECACHE_SOUND((char *)pRicSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pFootSounds ); i++ ) - PRECACHE_SOUND((char *)pFootSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pStompSounds ); i++ ) - PRECACHE_SOUND((char *)pStompSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pBreatheSounds ); i++ ) - PRECACHE_SOUND((char *)pBreatheSounds[i]); -} - - -void CGargantua::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TraceAttack\n"); - - if ( !IsAlive() ) - { - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); - return; - } - - // UNDONE: Hit group specific damage? - if ( bitsDamageType & (GARG_DAMAGE|DMG_BLAST) ) - { - if ( m_painSoundTime < gpGlobals->time ) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); - m_painSoundTime = gpGlobals->time + RANDOM_FLOAT( 2.5, 4 ); - } - } - - bitsDamageType &= GARG_DAMAGE; - - if ( bitsDamageType == 0) - { - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,100) < 20) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT(0.5,1.5) ); - pev->dmgtime = gpGlobals->time; -// if ( RANDOM_LONG(0,100) < 25 ) -// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - } - flDamage = 0; - } - - CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); - -} - - - -int CGargantua::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - ALERT( at_aiconsole, "CGargantua::TakeDamage\n"); - - if ( IsAlive() ) - { - if ( !(bitsDamageType & GARG_DAMAGE) ) - flDamage *= 0.01; - if ( bitsDamageType & DMG_BLAST ) - SetConditions( bits_COND_LIGHT_DAMAGE ); - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CGargantua::DeathEffect( void ) -{ - int i; - UTIL_MakeVectors(pev->angles); - Vector deathPos = pev->origin + gpGlobals->v_forward * 100; - - // Create a spiral of streaks - CSpiral::Create( deathPos, (pev->absmax.z - pev->absmin.z) * 0.6, 125, 1.5 ); - - Vector position = pev->origin; - position.z += 32; - for ( i = 0; i < 7; i+=2 ) - { - SpawnExplosion( position, 70, (i * 0.3), 60 + (i*20) ); - position.z += 15; - } - - CBaseEntity *pSmoker = CBaseEntity::Create( "env_smoker", pev->origin, g_vecZero, NULL ); - pSmoker->pev->health = 1; // 1 smoke balls - pSmoker->pev->scale = 46; // 4.6X normal size - pSmoker->pev->dmg = 0; // 0 radial distribution - pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds -} - - -void CGargantua::Killed( entvars_t *pevAttacker, int iGib ) -{ - EyeOff(); - UTIL_Remove( m_pEyeGlow ); - m_pEyeGlow = NULL; - CBaseMonster::Killed( pevAttacker, GIB_NEVER ); -} - -//========================================================= -// CheckMeleeAttack1 -// Garg swipe attack -// -//========================================================= -BOOL CGargantua::CheckMeleeAttack1( float flDot, float flDist ) -{ -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); - - if (flDot >= 0.7) - { - if (flDist <= GARG_ATTACKDIST) - return TRUE; - } - return FALSE; -} - - -// Flame thrower madness! -BOOL CGargantua::CheckMeleeAttack2( float flDot, float flDist ) -{ -// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist); - - if ( gpGlobals->time > m_flameTime ) - { - if (flDot >= 0.8 && flDist > GARG_ATTACKDIST) - { - if ( flDist <= GARG_FLAME_LENGTH ) - return TRUE; - } - } - return FALSE; -} - - -//========================================================= -// CheckRangeAttack1 -// flDot is the cos of the angle of the cone within which -// the attack can occur. -//========================================================= -// -// Stomp attack -// -//========================================================= -BOOL CGargantua::CheckRangeAttack1( float flDot, float flDist ) -{ - if ( gpGlobals->time > m_seeTime ) - { - if (flDot >= 0.7 && flDist > GARG_ATTACKDIST) - { - return TRUE; - } - } - return FALSE; -} - - - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGargantua::HandleAnimEvent(MonsterEvent_t *pEvent) -{ - switch( pEvent->event ) - { - case GARG_AE_SLASH_LEFT: - { - // HACKHACK!!! - CBaseEntity *pHurt = GargantuaCheckTraceHullAttack( GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH ); - if (pHurt) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.x = -30; // pitch - pHurt->pev->punchangle.y = -30; // yaw - pHurt->pev->punchangle.z = 30; // roll - //UTIL_MakeVectors(pev->angles); // called by CheckTraceHullAttack - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN ( edict(), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0,15) ); - - Vector forward; - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - } - break; - - case GARG_AE_RIGHT_FOOT: - case GARG_AE_LEFT_FOOT: - UTIL_ScreenShake( pev->origin, 4.0, 3.0, 1.0, 750 ); - EMIT_SOUND_DYN ( edict(), CHAN_BODY, pFootSounds[ RANDOM_LONG(0,ARRAYSIZE(pFootSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - break; - - case GARG_AE_STOMP: - StompAttack(); - m_seeTime = gpGlobals->time + 12; - break; - - case GARG_AE_BREATHE: - EMIT_SOUND_DYN ( edict(), CHAN_VOICE, pBreatheSounds[ RANDOM_LONG(0,ARRAYSIZE(pBreatheSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10,10) ); - break; - - default: - CBaseMonster::HandleAnimEvent(pEvent); - break; - } -} - - -//========================================================= -// CheckTraceHullAttack - expects a length to trace, amount -// of damage to do, and damage type. Returns a pointer to -// the damaged entity in case the monster wishes to do -// other stuff to the victim (punchangle, etc) -// Used for many contact-range melee attacks. Bites, claws, etc. - -// Overridden for Gargantua because his swing starts lower as -// a percentage of his height (otherwise he swings over the -// players head) -//========================================================= -CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += 64; - Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if ( iDamage > 0 ) - { - pEntity->TakeDamage( pev, pev, iDamage, iDmgType ); - } - - return pEntity; - } - - return NULL; -} - - -Schedule_t *CGargantua::GetScheduleOfType( int Type ) -{ - // HACKHACK - turn off the flames if they are on and garg goes scripted / dead - if ( FlameIsOn() ) - FlameDestroy(); - - switch( Type ) - { - case SCHED_MELEE_ATTACK2: - return slGargFlame; - case SCHED_MELEE_ATTACK1: - return slGargSwipe; - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -void CGargantua::StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_FLAME_SWEEP: - FlameCreate(); - m_flWaitFinished = gpGlobals->time + pTask->flData; - m_flameTime = gpGlobals->time + 6; - m_flameX = 0; - m_flameY = 0; - break; - - case TASK_SOUND_ATTACK: - if ( RANDOM_LONG(0,100) < 30 ) - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_GARG, 0, PITCH_NORM ); - TaskComplete(); - break; - - case TASK_DIE: - m_flWaitFinished = gpGlobals->time + 1.6; - DeathEffect(); - // FALL THROUGH - default: - CBaseMonster::StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CGargantua::RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_DIE: - if ( gpGlobals->time > m_flWaitFinished ) - { - pev->renderfx = kRenderFxExplode; - pev->rendercolor.x = 255; - pev->rendercolor.y = 0; - pev->rendercolor.z = 0; - StopAnimation(); - pev->nextthink = gpGlobals->time + 0.15; - SetThink( &CGargantua::SUB_Remove ); - int i; - int parts = MODEL_FRAMES( gGargGibModel ); - for ( i = 0; i < 10; i++ ) - { - CGib *pGib = GetClassPtr( (CGib *)NULL ); - - pGib->Spawn( GARG_GIB_MODEL ); - - int bodyPart = 0; - if ( parts > 1 ) - bodyPart = RANDOM_LONG( 0, pev->body-1 ); - - pGib->pev->body = bodyPart; - pGib->m_bloodColor = BLOOD_COLOR_YELLOW; - pGib->m_material = matNone; - pGib->pev->origin = pev->origin; - pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT( 300, 500 ); - pGib->pev->nextthink = gpGlobals->time + 1.25; - pGib->SetThink( &CGib::SUB_FadeOut ); - } - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - - // size - WRITE_COORD( 200 ); - WRITE_COORD( 200 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - WRITE_COORD( 0 ); - - // randomization - WRITE_BYTE( 200 ); - - // Model - WRITE_SHORT( gGargGibModel ); //model id# - - // # of shards - WRITE_BYTE( 50 ); - - // duration - WRITE_BYTE( 20 );// 3.0 seconds - - // flags - - WRITE_BYTE( BREAK_FLESH ); - MESSAGE_END(); - - return; - } - else - CBaseMonster::RunTask(pTask); - break; - - case TASK_FLAME_SWEEP: - if ( gpGlobals->time > m_flWaitFinished ) - { - FlameDestroy(); - TaskComplete(); - FlameControls( 0, 0 ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - } - else - { - BOOL cancel = FALSE; - - Vector angles = g_vecZero; - - FlameUpdate(); - CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy ) - { - Vector org = pev->origin; - org.z += 64; - Vector dir = pEnemy->BodyTarget(org) - org; - angles = UTIL_VecToAngles( dir ); - angles.x = -angles.x; - angles.y -= pev->angles.y; - if ( dir.Length() > 400 ) - cancel = TRUE; - } - if ( fabs(angles.y) > 60 ) - cancel = TRUE; - - if ( cancel ) - { - m_flWaitFinished -= 0.5; - m_flameTime -= 0.5; - } - // FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) ); - FlameControls( angles.x, angles.y ); - } - break; - - default: - CBaseMonster::RunTask( pTask ); - break; - } -} - - -class CSmoker : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( env_smoker, CSmoker ); - -void CSmoker::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - - -void CSmoker::Think( void ) -{ - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -pev->dmg, pev->dmg )); - WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -pev->dmg, pev->dmg )); - WRITE_COORD( pev->origin.z); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(pev->scale, pev->scale * 1.1) ); - WRITE_BYTE( RANDOM_LONG(8,14) ); // framerate - MESSAGE_END(); - - pev->health--; - if ( pev->health > 0 ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2); - else - UTIL_Remove( this ); -} - - -void CSpiral::Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time; - pev->solid = SOLID_NOT; - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - pev->effects |= EF_NODRAW; - pev->angles = g_vecZero; -} - - -CSpiral *CSpiral::Create( const Vector &origin, float height, float radius, float duration ) -{ - if ( duration <= 0 ) - return NULL; - - CSpiral *pSpiral = GetClassPtr( (CSpiral *)NULL ); - pSpiral->Spawn(); - pSpiral->pev->dmgtime = pSpiral->pev->nextthink; - pSpiral->pev->origin = origin; - pSpiral->pev->scale = radius; - pSpiral->pev->dmg = height; - pSpiral->pev->speed = duration; - pSpiral->pev->health = 0; - pSpiral->pev->angles = g_vecZero; - - return pSpiral; -} - -#define SPIRAL_INTERVAL 0.1 //025 - -void CSpiral::Think( void ) -{ - float time = gpGlobals->time - pev->dmgtime; - - while ( time > SPIRAL_INTERVAL ) - { - Vector position = pev->origin; - Vector direction = Vector(0,0,1); - - float fraction = 1.0 / pev->speed; - - float radius = (pev->scale * pev->health) * fraction; - - position.z += (pev->health * pev->dmg) * fraction; - pev->angles.y = (pev->health * 360 * 8) * fraction; - UTIL_MakeVectors( pev->angles ); - position = position + gpGlobals->v_forward * radius; - direction = (direction + gpGlobals->v_forward).Normalize(); - - StreakSplash( position, Vector(0,0,1), RANDOM_LONG(8,11), 20, RANDOM_LONG(50,150), 400 ); - - // Jeez, how many counters should this take ? :) - pev->dmgtime += SPIRAL_INTERVAL; - pev->health += SPIRAL_INTERVAL; - time -= SPIRAL_INTERVAL; - } - - pev->nextthink = gpGlobals->time; - - if ( pev->health >= pev->speed ) - UTIL_Remove( this ); -} - - -// HACKHACK Cut and pasted from explode.cpp -void SpawnExplosion( Vector center, float randomRange, float time, int magnitude ) -{ - KeyValueData kvd; - char buf[128]; - - center.x += RANDOM_FLOAT( -randomRange, randomRange ); - center.y += RANDOM_FLOAT( -randomRange, randomRange ); - - CBaseEntity *pExplosion = CBaseEntity::Create( "env_explosion", center, g_vecZero, NULL ); - sprintf( buf, "%3d", magnitude ); - kvd.szKeyName = "iMagnitude"; - kvd.szValue = buf; - pExplosion->KeyValue( &kvd ); - pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE; - - pExplosion->Spawn(); - pExplosion->SetThink( &CBaseEntity::SUB_CallUseToggle ); - pExplosion->pev->nextthink = gpGlobals->time + time; -} - - - -#endif diff --git a/sdk/dlls/gauss.cpp b/sdk/dlls/gauss.cpp deleted file mode 100644 index 1caa927..0000000 --- a/sdk/dlls/gauss.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "shake.h" -#include "gamerules.h" - - -#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged - -enum gauss_e { - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); - -float CGauss::GetFullChargeTime( void ) -{ -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - return 1.5; - } - - return 4; -} - -#ifdef CLIENT_DLL -extern int g_irunninggausspred; -#endif - -void CGauss::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_GAUSS; - SET_MODEL(ENT(pev), "models/w_gauss.mdl"); - - m_iDefaultAmmo = GAUSS_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGauss::Precache( void ) -{ - PRECACHE_MODEL("models/w_gauss.mdl"); - PRECACHE_MODEL("models/v_gauss.mdl"); - PRECACHE_MODEL("models/p_gauss.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND("weapons/gauss2.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("weapons/electro5.wav"); - PRECACHE_SOUND("weapons/electro6.wav"); - PRECACHE_SOUND("ambience/pulsemachine.wav"); - - m_iGlow = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBalls = PRECACHE_MODEL( "sprites/hotglow.spr" ); - m_iBeam = PRECACHE_MODEL( "sprites/smoke.spr" ); - - m_usGaussFire = PRECACHE_EVENT( 1, "events/gauss.sc" ); - m_usGaussSpin = PRECACHE_EVENT( 1, "events/gaussspin.sc" ); -} - -int CGauss::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CGauss::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "uranium"; - p->iMaxAmmo1 = URANIUM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 1; - p->iId = m_iId = WEAPON_GAUSS; - p->iFlags = 0; - p->iWeight = GAUSS_WEIGHT; - - return 1; -} - -BOOL CGauss::Deploy( ) -{ - m_pPlayer->m_flPlayAftershock = 0.0; - return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); -} - -void CGauss::Holster( int skiplocal /* = 0 */ ) -{ - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_GLOBAL, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( GAUSS_HOLSTER ); - m_fInAttack = 0; -} - - -void CGauss::PrimaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - PlayEmptySound( ); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay(0.15); - return; - } - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) - { - PlayEmptySound( ); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - m_fPrimaryFire = TRUE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 2; - - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; -} - -void CGauss::SecondaryAttack() -{ - // don't fire underwater - if ( m_pPlayer->pev->waterlevel == 3 ) - { - if ( m_fInAttack != 0 ) - { - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - SendWeaponAnim( GAUSS_IDLE ); - m_fInAttack = 0; - } - else - { - PlayEmptySound( ); - } - - m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - return; - } - - if ( m_fInAttack == 0 ) - { - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - return; - } - - m_fPrimaryFire = FALSE; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); - - // spin up - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - SendWeaponAnim( GAUSS_SPINUP ); - m_fInAttack = 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - m_pPlayer->m_flStartCharge = gpGlobals->time; - m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; - } - else if (m_fInAttack == 1) - { - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) - { - SendWeaponAnim( GAUSS_SPIN ); - m_fInAttack = 2; - } - } - else - { - // during the charging process, eat one bit of ammo every once in a while - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) - { -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; - } - else - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; - } - } - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // out of ammo! force the gun to fire - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; - return; - } - - if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) - { - // don't eat any more ammo after gun is fully charged. - m_pPlayer->m_flNextAmmoBurn = 1000; - } - - int pitch = static_cast(( gpGlobals->time - m_pPlayer->m_flStartCharge ) * ( 150 / GetFullChargeTime() ) + 100); - if ( pitch > 250 ) - pitch = 250; - - // ALERT( at_console, "%d %d %d\n", m_fInAttack, m_iSoundState, pitch ); - - if ( m_iSoundState == 0 ) - ALERT( at_console, "sound state %d\n", m_iSoundState ); - - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - - // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; - if ( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) - { - // Player charged up too long. Zap him. - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, 80 + RANDOM_LONG(0,0x3f)); - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f)); - - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - -#ifndef CLIENT_DLL - m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); - UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); -#endif - SendWeaponAnim( GAUSS_IDLE ); - - // Player may have been killed and this weapon dropped, don't execute any more code after this! - return; - } - } -} - -//========================================================= -// StartFire- since all of this code has to run and then -// call Fire(), it was easier at this point to rip it out -// of weaponidle() and make its own function then to try to -// merge this into Fire(), which has some identical variable names -//========================================================= -void CGauss::StartFire( void ) -{ - float flDamage; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecAiming = gpGlobals->v_forward; - Vector vecSrc = m_pPlayer->GetGunPosition( ); // + gpGlobals->v_up * -8 + gpGlobals->v_right * 8; - - if ( gpGlobals->time - m_pPlayer->m_flStartCharge > GetFullChargeTime() ) - { - flDamage = 200; - } - else - { - flDamage = 200 * (( gpGlobals->time - m_pPlayer->m_flStartCharge) / GetFullChargeTime() ); - } - - if ( m_fPrimaryFire ) - { - // fixed damage on primary attack -#ifdef CLIENT_DLL - flDamage = 20; -#else - flDamage = gSkillData.plrDmgGauss; -#endif - } - - if (m_fInAttack != 3) - { - //ALERT ( at_console, "Time:%f Damage:%f\n", gpGlobals->time - m_pPlayer->m_flStartCharge, flDamage ); - -#ifndef CLIENT_DLL - float flZVel = m_pPlayer->pev->velocity.z; - - if ( !m_fPrimaryFire ) - { - m_pPlayer->pev->velocity = m_pPlayer->pev->velocity - gpGlobals->v_forward * flDamage * 5; - } - - if ( !g_pGameRules->IsMultiplayer() ) - - { - // in deathmatch, gauss can pop you up into the air. Not in single play. - m_pPlayer->pev->velocity.z = flZVel; - } -#endif - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - } - - // time until aftershock 'static discharge' sound - m_pPlayer->m_flPlayAftershock = gpGlobals->time + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.3, 0.8 ); - - Fire( vecSrc, vecAiming, flDamage ); -} - -void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) -{ - m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - TraceResult tr, beam_tr; - -#ifndef CLIENT_DLL - Vector vecSrc = vecOrigSrc; - Vector vecDest = vecSrc + vecDir * 8192; - float flMaxFrac = 1.0; - int nTotal = 0; - int fHasPunched = 0; - int fFirstBeam = 1; - int nMaxHits = 10; - edict_t *pentIgnore = ENT( m_pPlayer->pev ); -#endif - -#ifdef CLIENT_DLL - if ( m_fPrimaryFire == false ) - g_irunninggausspred = true; -#endif - - // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); - - // This reliable event is used to stop the spinning sound - // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client - // It's sent reliably anyway, which could lead to other delays - - PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - - - /*ALERT( at_console, "%f %f %f\n%f %f %f\n", - vecSrc.x, vecSrc.y, vecSrc.z, - vecDest.x, vecDest.y, vecDest.z );*/ - - -// ALERT( at_console, "%f %f\n", tr.flFraction, flMaxFrac ); - -#ifndef CLIENT_DLL - while (flDamage > 10 && nMaxHits > 0) - { - nMaxHits--; - - // ALERT( at_console, "." ); - UTIL_TraceLine(vecSrc, vecDest, dont_ignore_monsters, pentIgnore, &tr); - - if (tr.fAllSolid) - break; - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - - if (pEntity == NULL) - break; - - if ( fFirstBeam ) - { - m_pPlayer->pev->effects |= EF_MUZZLEFLASH; - fFirstBeam = 0; - - nTotal += 26; - } - - if (pEntity->pev->takedamage) - { - ClearMultiDamage(); - pEntity->TraceAttack( m_pPlayer->pev, flDamage, vecDir, &tr, DMG_BULLET ); - ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - } - - if ( pEntity->ReflectGauss() ) - { - float n; - - pentIgnore = NULL; - - n = -DotProduct(tr.vecPlaneNormal, vecDir); - - if (n < 0.5) // 60 degrees - { - // ALERT( at_console, "reflect %f\n", n ); - // reflect - Vector r; - - r = 2.0 * tr.vecPlaneNormal * n + vecDir; - flMaxFrac = flMaxFrac - tr.flFraction; - vecDir = r; - vecSrc = tr.vecEndPos + vecDir * 8; - vecDest = vecSrc + vecDir * 8192; - - // explode a bit - m_pPlayer->RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, flDamage * n, CLASS_NONE, DMG_BLAST ); - - nTotal += 34; - - // lose energy - if (n == 0) n = 0.1; - flDamage = flDamage * (1 - n); - } - else - { - nTotal += 13; - - // limit it to one hole punch - if (fHasPunched) - break; - fHasPunched = 1; - - // try punching through wall if secondary attack (primary is incapable of breaking through) - if ( !m_fPrimaryFire ) - { - UTIL_TraceLine( tr.vecEndPos + vecDir * 8, vecDest, dont_ignore_monsters, pentIgnore, &beam_tr); - if (!beam_tr.fAllSolid) - { - // trace backwards to find exit point - UTIL_TraceLine( beam_tr.vecEndPos, tr.vecEndPos, dont_ignore_monsters, pentIgnore, &beam_tr); - - float n = (beam_tr.vecEndPos - tr.vecEndPos).Length( ); - - if (n < flDamage) - { - if (n == 0) n = 1; - flDamage -= n; - - // ALERT( at_console, "punch %f\n", n ); - nTotal += 21; - - // exit blast damage - //m_pPlayer->RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, CLASS_NONE, DMG_BLAST ); - float damage_radius; - - - if ( g_pGameRules->IsMultiplayer() ) - { - damage_radius = flDamage * 1.75; // Old code == 2.5 - } - else - { - damage_radius = flDamage * 2.5; - } - - ::RadiusDamage( beam_tr.vecEndPos + vecDir * 8, pev, m_pPlayer->pev, flDamage, damage_radius, CLASS_NONE, DMG_BLAST ); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - - nTotal += 53; - - vecSrc = beam_tr.vecEndPos + vecDir; - } - } - else - { - //ALERT( at_console, "blocked %f\n", n ); - flDamage = 0; - } - } - else - { - //ALERT( at_console, "blocked solid\n" ); - - flDamage = 0; - } - - } - } - else - { - vecSrc = tr.vecEndPos + vecDir; - pentIgnore = ENT( pEntity->pev ); - } - } -#endif - // ALERT( at_console, "%d bytes\n", nTotal ); -} - - - - -void CGauss::WeaponIdle( void ) -{ - ResetEmptySound( ); - - // play aftershock static discharge - if ( m_pPlayer->m_flPlayAftershock && m_pPlayer->m_flPlayAftershock < gpGlobals->time ) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro4.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro5.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/electro6.wav", RANDOM_FLOAT(0.7, 0.8), ATTN_NORM); break; - case 3: break; // no sound - } - m_pPlayer->m_flPlayAftershock = 0.0; - } - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - - if (m_fInAttack != 0) - { - StartFire(); - m_fInAttack = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; - } - else - { - int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.5) - { - iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else if (flRand <= 0.75) - { - iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } - else - { - iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - } - - return; - SendWeaponAnim( iAnim ); - - } -} - - - - - - -class CGaussAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_gaussammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_gaussammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_URANIUMBOX_GIVE, "uranium", URANIUM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_gaussclip, CGaussAmmo ); - -#endif diff --git a/sdk/dlls/genericmonster.cpp b/sdk/dlls/genericmonster.cpp deleted file mode 100644 index a689897..0000000 --- a/sdk/dlls/genericmonster.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Generic Monster - purely for scripted sequence work. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -// For holograms, make them not solid so the player can walk through them -#define SF_GENERICMONSTER_NOTSOLID 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGenericMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGenericMonster :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGenericMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGenericMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGenericMonster :: ISoundMask ( void ) -{ - return 0; -} - -//========================================================= -// Spawn -//========================================================= -void CGenericMonster :: Spawn() -{ - Precache(); - - SET_MODEL( ENT(pev), STRING(pev->model) ); - -/* - if ( FStrEq( STRING(pev->model), "models/player.mdl" ) ) - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); -*/ - - if ( FStrEq( STRING(pev->model), "models/player.mdl" ) || FStrEq( STRING(pev->model), "models/holo.mdl" ) ) - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - - if ( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGenericMonster :: Precache() -{ - PRECACHE_MODEL( (char *)STRING(pev->model) ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/sdk/dlls/ggrenade.cpp b/sdk/dlls/ggrenade.cpp deleted file mode 100644 index 19be84b..0000000 --- a/sdk/dlls/ggrenade.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== generic grenade.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" - - -//===================grenade - - -LINK_ENTITY_TO_CLASS( grenade, CGrenade ); - -// Grenades flagged with this will be triggered when the owner calls detonateSatchelCharges -#define SF_DETONATE 0x0001 - -// -// Grenade Explode -// -void CGrenade::Explode( Vector vecSrc, Vector vecAim ) -{ - TraceResult tr; - UTIL_TraceLine ( pev->origin, pev->origin + Vector ( 0, 0, -32 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr, DMG_BLAST ); -} - -// UNDONE: temporary scorching for PreAlpha - find a less sleazy permenant solution. -void CGrenade::Explode( TraceResult *pTrace, int bitsDamageType ) -{ -// float flRndSound;// sound randomizer - - pev->model = iStringNull;//invisible - pev->solid = SOLID_NOT;// intangible - - pev->takedamage = DAMAGE_NO; - - // Pull out of the wall a bit - if ( pTrace->flFraction != 1.0 ) - { - pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6); - } - - int iContents = UTIL_PointContents ( pev->origin ); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound - WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - if (iContents != CONTENTS_WATER) - { - WRITE_SHORT( g_sModelIndexFireball ); - } - else - { - WRITE_SHORT( g_sModelIndexWExplosion ); - } - WRITE_BYTE( static_cast((pev->dmg - 50) * .60) ); // scale * 10 - WRITE_BYTE( 15 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); - entvars_t *pevOwner; - if ( pev->owner ) - pevOwner = VARS( pev->owner ); - else - pevOwner = NULL; - - pev->owner = NULL; // can't traceline attack owner if this is set - - RadiusDamage ( pev, pevOwner, pev->dmg, CLASS_NONE, bitsDamageType ); - - if ( RANDOM_FLOAT( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); - } - -// flRndSound = RANDOM_FLOAT( 0 , 1 ); - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM); break; - } - - pev->effects |= EF_NODRAW; - SetThink( &CGrenade::Smoke ); - pev->velocity = g_vecZero; - pev->nextthink = gpGlobals->time + 0.3; - - if (iContents != CONTENTS_WATER) - { - int sparkCount = RANDOM_LONG(0,3); - for ( int i = 0; i < sparkCount; i++ ) - Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL ); - } -} - - -void CGrenade::Smoke( void ) -{ - if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) - { - UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 ); - } - else - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( static_cast((pev->dmg - 50) * 0.80) ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - } - UTIL_Remove( this ); -} - -void CGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - Detonate( ); -} - - -// Timed grenade, this think is called when time runs out. -void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time; -} - -void CGrenade::PreDetonate( void ) -{ - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, 400, 0.3 ); - - SetThink( &CGrenade::Detonate ); - pev->nextthink = gpGlobals->time + 1; -} - - -void CGrenade::Detonate( void ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 ); - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ), ignore_monsters, ENT(pev), & tr); - - Explode( &tr, DMG_BLAST ); -} - - -// -// Contact grenade, explode when it touches something -// -void CGrenade::ExplodeTouch( CBaseEntity *pOther ) -{ - TraceResult tr; - Vector vecSpot;// trace starts here! - - pev->enemy = pOther->edict(); - - vecSpot = pev->origin - pev->velocity.Normalize() * 32; - UTIL_TraceLine( vecSpot, vecSpot + pev->velocity.Normalize() * 64, ignore_monsters, ENT(pev), &tr ); - - Explode( &tr, DMG_BLAST ); -} - - -void CGrenade::DangerSoundThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * 0.5, static_cast(pev->velocity.Length( )), 0.2 ); - pev->nextthink = gpGlobals->time + 0.2; - - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - } -} - - -void CGrenade::BounceTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // only do damage if we're moving fairly fast - if (m_flNextAttack < gpGlobals->time && pev->velocity.Length() > 100) - { - entvars_t *pevOwner = VARS( pev->owner ); - if (pevOwner) - { - TraceResult tr = UTIL_GetGlobalTrace( ); - ClearMultiDamage( ); - pOther->TraceAttack(pevOwner, 1, gpGlobals->v_forward, &tr, DMG_CLUB ); - ApplyMultiDamage( pev, pevOwner); - } - m_flNextAttack = gpGlobals->time + 1.0; // debounce - } - - Vector vecTestVelocity; - // pev->avelocity = Vector (300, 300, 300); - - // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical - // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. - // trimming the Z velocity a bit seems to help quite a bit. - vecTestVelocity = pev->velocity; - vecTestVelocity.z *= 0.45; - - if ( !m_fRegisteredSound && vecTestVelocity.Length() <= 60 ) - { - //ALERT( at_console, "Grenade Registered!: %f\n", vecTestVelocity.Length() ); - - // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. - // go ahead and emit the danger sound. - - // register a radius louder than the explosion, so we make sure everyone gets out of the way - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin, static_cast(pev->dmg / 0.4), 0.3 ); - m_fRegisteredSound = TRUE; - } - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.8; - - pev->sequence = RANDOM_LONG( 1, 1 ); - } - else - { - // play bounce sound - BounceSound(); - } - pev->framerate = pev->velocity.Length() / 200.0; - if (pev->framerate > 1.0) - pev->framerate = 1; - else if (pev->framerate < 0.5) - pev->framerate = 0; - -} - - - -void CGrenade::SlideTouch( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - - if (pev->flags & FL_ONGROUND) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - - if (pev->velocity.x != 0 || pev->velocity.y != 0) - { - // maintain sliding sound - } - } - else - { - BounceSound(); - } -} - -void CGrenade :: BounceSound( void ) -{ - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit1.wav", 0.25, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit2.wav", 0.25, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/grenade_hit3.wav", 0.25, ATTN_NORM); break; - } -} - -void CGrenade :: TumbleThink( void ) -{ - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->dmgtime - 1 < gpGlobals->time) - { - CSoundEnt::InsertSound ( bits_SOUND_DANGER, pev->origin + pev->velocity * (pev->dmgtime - gpGlobals->time), 400, 0.1 ); - } - - if (pev->dmgtime <= gpGlobals->time) - { - SetThink( &CGrenade::Detonate ); - } - if (pev->waterlevel != 0) - { - pev->velocity = pev->velocity * 0.5; - pev->framerate = 0.2; - } -} - - -void CGrenade:: Spawn( void ) -{ - pev->movetype = MOVETYPE_BOUNCE; - pev->classname = MAKE_STRING( "grenade" ); - - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/grenade.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pev->dmg = 100; - m_fRegisteredSound = FALSE; -} - - -CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - // contact grenades arc lower - pGrenade->pev->gravity = 0.5;// lower gravity since grenade is aerodynamic and engine doesn't know it. - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles (pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - // make monsters afaid of it while in the air - pGrenade->SetThink( &CGrenade::DangerSoundThink ); - pGrenade->pev->nextthink = gpGlobals->time; - - // Tumble in air - pGrenade->pev->avelocity.x = RANDOM_FLOAT ( -100, -500 ); - - // Explode on contact - pGrenade->SetTouch( &CGrenade::ExplodeTouch ); - - pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade; - - return pGrenade; -} - - -CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->Spawn(); - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity); - pGrenade->pev->owner = ENT(pevOwner); - - pGrenade->SetTouch( &CGrenade::BounceTouch ); // Bounce if touched - - // Take one second off of the desired detonation time and set the think to PreDetonate. PreDetonate - // will insert a DANGER sound into the world sound list and delay detonation for one second so that - // the grenade explodes after the exact amount of time specified in the call to ShootTimed(). - - pGrenade->pev->dmgtime = gpGlobals->time + time; - pGrenade->SetThink( &CGrenade::TumbleThink ); - pGrenade->pev->nextthink = gpGlobals->time + 0.1; - if (time < 0.1) - { - pGrenade->pev->nextthink = gpGlobals->time; - pGrenade->pev->velocity = Vector( 0, 0, 0 ); - } - - pGrenade->pev->sequence = RANDOM_LONG( 3, 6 ); - pGrenade->pev->framerate = 1.0; - - // Tumble through the air - // pGrenade->pev->avelocity.x = -400; - - pGrenade->pev->gravity = 0.5; - pGrenade->pev->friction = 0.8; - - SET_MODEL(ENT(pGrenade->pev), "models/w_grenade.mdl"); - pGrenade->pev->dmg = 100; - - return pGrenade; -} - - -CGrenade * CGrenade :: ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ) -{ - CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL ); - pGrenade->pev->movetype = MOVETYPE_BOUNCE; - pGrenade->pev->classname = MAKE_STRING( "grenade" ); - - pGrenade->pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pGrenade->pev), "models/grenade.mdl"); // Change this to satchel charge model - - UTIL_SetSize(pGrenade->pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - - pGrenade->pev->dmg = 200; - UTIL_SetOrigin( pGrenade->pev, vecStart ); - pGrenade->pev->velocity = vecVelocity; - pGrenade->pev->angles = g_vecZero; - pGrenade->pev->owner = ENT(pevOwner); - - // Detonate in "time" seconds - pGrenade->SetThink( &CGrenade::SUB_DoNothing ); - pGrenade->SetUse( &CGrenade::DetonateUse ); - pGrenade->SetTouch( &CGrenade::SlideTouch ); - pGrenade->pev->spawnflags = SF_DETONATE; - - pGrenade->pev->friction = 0.9; - - return pGrenade; -} - - - -void CGrenade :: UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ) -{ - edict_t *pentFind; - edict_t *pentOwner; - - if ( !pevOwner ) - return; - - CBaseEntity *pOwner = CBaseEntity::Instance( pevOwner ); - - pentOwner = pOwner->edict(); - - pentFind = FIND_ENTITY_BY_CLASSNAME( NULL, "grenade" ); - while ( !FNullEnt( pentFind ) ) - { - CBaseEntity *pEnt = Instance( pentFind ); - if ( pEnt ) - { - if ( FBitSet( pEnt->pev->spawnflags, SF_DETONATE ) && pEnt->pev->owner == pentOwner ) - { - if ( code == SATCHEL_DETONATE ) - pEnt->Use( pOwner, pOwner, USE_ON, 0 ); - else // SATCHEL_RELEASE - pEnt->pev->owner = NULL; - } - } - pentFind = FIND_ENTITY_BY_CLASSNAME( pentFind, "grenade" ); - } -} - -//======================end grenade - diff --git a/sdk/dlls/globals.cpp b/sdk/dlls/globals.cpp deleted file mode 100644 index ef657c2..0000000 --- a/sdk/dlls/globals.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== globals.cpp ======================================================== - - DLL-wide global variable definitions. - They're all defined here, for convenient centralization. - Source files that need them should "extern ..." declare each - variable, to better document what globals they care about. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "soundent.h" - -DLL_GLOBAL ULONG g_ulFrameCount; -DLL_GLOBAL ULONG g_ulModelIndexEyes; -DLL_GLOBAL ULONG g_ulModelIndexPlayer; -DLL_GLOBAL Vector g_vecAttackDir; -DLL_GLOBAL int g_iSkillLevel; -DLL_GLOBAL int gDisplayTitle; -DLL_GLOBAL BOOL g_fGameOver; -DLL_GLOBAL const Vector g_vecZero = Vector(0,0,0); -DLL_GLOBAL int g_Language; diff --git a/sdk/dlls/glock.cpp b/sdk/dlls/glock.cpp deleted file mode 100644 index 9799c2b..0000000 --- a/sdk/dlls/glock.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -class CGlock : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 2; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); - BOOL Deploy( void ); - void Reload( void ); - void WeaponIdle( void ); - -private: - int m_iShell; - - - unsigned short m_usFireGlock1; - unsigned short m_usFireGlock2; -}; -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - - -void CGlock::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_GLOCK; - SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); - - PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -BOOL CGlock::Deploy( ) -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded" ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ - GlockFire( 0.01, 0.3, TRUE ); -} - -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) -{ - if (m_iClip <= 0) - { - if (m_fFireOnEmpty) - { - PlayEmptySound(); - m_flNextPrimaryAttack = gpGlobals->time + 0.2; - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - -#if defined ( OLD_WEAPONS ) - if (m_iClip != 0) - SendWeaponAnim( GLOCK_SHOOT ); - else - SendWeaponAnim( GLOCK_SHOOT_EMPTY ); -#endif - - if ( fUseAutoAim ) - { - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock1, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - } - else - { - PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#if defined ( OLD_WEAPONS ) - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecShellVelocity = m_pPlayer->pev->velocity - + gpGlobals->v_right * RANDOM_FLOAT(50,70) - + gpGlobals->v_up * RANDOM_FLOAT(100,150) - + gpGlobals->v_forward * 25; - EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); -#endif - - // silenced - if (pev->body == 1) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); - break; - } -#endif - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; -#if defined ( OLD_WEAPONS ) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); -#endif - } - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming; - - if ( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - -#if defined ( OLD_WEAPONS ) - m_pPlayer->pev->punchangle.x -= 2; -#endif -} - - -void CGlock::Reload( void ) -{ - int iResult; - - if (m_iClip == 0) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if (iResult) - { - m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); - } -} - - - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if (m_flTimeWeaponIdle > gpGlobals->time) - return; - - // only idle if the slid isn't back - if (m_iClip != 0) - { - int iAnim; - float flRand = RANDOM_FLOAT(0, 1); - if (flRand <= 0.3 + 0 * 0.75) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; - } - else if (flRand <= 0.6 + 0 * 0.875) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; - } - SendWeaponAnim( iAnim ); - } -} - - - - - - - - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - - diff --git a/sdk/dlls/gman.cpp b/sdk/dlls/gman.cpp deleted file mode 100644 index 9a8e30c..0000000 --- a/sdk/dlls/gman.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// GMan - misunderstood servant of the people -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "weapons.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CGMan : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - - EHANDLE m_hPlayer; - EHANDLE m_hTalkTarget; - float m_flTalkTime; -}; -LINK_ENTITY_TO_CLASS( monster_gman, CGMan ); - - -TYPEDESCRIPTION CGMan::m_SaveData[] = -{ - DEFINE_FIELD( CGMan, m_hTalkTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CGMan, m_flTalkTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CGMan, CBaseMonster ); - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CGMan :: Classify ( void ) -{ - return CLASS_NONE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CGMan :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CGMan :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - generic monster can't hear. -//========================================================= -int CGMan :: ISoundMask ( void ) -{ - return 0; -} - -//========================================================= -// Spawn -//========================================================= -void CGMan :: Spawn() -{ - Precache(); - - SET_MODEL( ENT(pev), "models/gman.mdl" ); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = DONT_BLEED; - pev->health = 100; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CGMan :: Precache() -{ - PRECACHE_MODEL( "models/gman.mdl" ); -} - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - -void CGMan :: StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - if (m_hPlayer == 0) - { - m_hPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - } - break; - } - CBaseMonster::StartTask( pTask ); -} - -void CGMan :: RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_WAIT: - // look at who I'm talking to - if (m_flTalkTime > gpGlobals->time && m_hTalkTarget != 0) - { - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - // look at player, but only if playing a "safe" idle animation - else if (m_hPlayer != 0 && pev->sequence == 0) - { - float yaw = VecToYaw(m_hPlayer->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } - else - { - SetBoneController( 0, 0 ); - } - CBaseMonster::RunTask( pTask ); - break; - default: - SetBoneController( 0, 0 ); - CBaseMonster::RunTask( pTask ); - break; - } -} - - -//========================================================= -// Override all damage -//========================================================= -int CGMan :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->health = pev->max_health / 2; // always trigger the 50% damage aitrigger - - if ( flDamage > 0 ) - { - SetConditions(bits_COND_LIGHT_DAMAGE); - } - - if ( flDamage >= 20 ) - { - SetConditions(bits_COND_HEAVY_DAMAGE); - } - return TRUE; -} - - -void CGMan::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - - -void CGMan::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - CBaseMonster::PlayScriptedSentence( pszSentence, duration, volume, attenuation, bConcurrent, pListener ); - - m_flTalkTime = gpGlobals->time + duration; - m_hTalkTarget = pListener; -} diff --git a/sdk/dlls/h_ai.cpp b/sdk/dlls/h_ai.cpp deleted file mode 100644 index 73a5064..0000000 --- a/sdk/dlls/h_ai.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - - h_ai.cpp - halflife specific ai code - -*/ - - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "game.h" - -#define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a monster looking for lateral cover -#define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a monster looking for lateral cover - -//float flRandom = RANDOM_FLOAT(0,1); - -DLL_GLOBAL BOOL g_fDrawLines = FALSE; - -//========================================================= -// -// AI UTILITY FUNCTIONS -// -// !!!UNDONE - move CBaseMonster functions to monsters.cpp -//========================================================= - -//========================================================= -// FBoxVisible - a more accurate ( and slower ) version -// of FVisible. -// -// !!!UNDONE - make this CBaseMonster? -//========================================================= -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize ) -{ - // don't look through water - if ((pevLooker->waterlevel != 3 && pevTarget->waterlevel == 3) - || (pevLooker->waterlevel == 3 && pevTarget->waterlevel == 0)) - return FALSE; - - TraceResult tr; - Vector vecLookerOrigin = pevLooker->origin + pevLooker->view_ofs;//look through the monster's 'eyes' - for (int i = 0; i < 5; i++) - { - Vector vecTarget = pevTarget->origin; - vecTarget.x += RANDOM_FLOAT( pevTarget->mins.x + flSize, pevTarget->maxs.x - flSize); - vecTarget.y += RANDOM_FLOAT( pevTarget->mins.y + flSize, pevTarget->maxs.y - flSize); - vecTarget.z += RANDOM_FLOAT( pevTarget->mins.z + flSize, pevTarget->maxs.z - flSize); - - UTIL_TraceLine(vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, ENT(pevLooker)/*pentIgnore*/, &tr); - - if (tr.flFraction == 1.0) - { - vecTargetOrigin = vecTarget; - return TRUE;// line of sight is valid. - } - } - return FALSE;// Line of sight is not established -} - -// -// VecCheckToss - returns the velocity at which an object should be lobbed from vecspot1 to land near vecspot2. -// returns g_vecZero if toss is not feasible. -// -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj ) -{ - TraceResult tr; - Vector vecMidPoint;// halfway point between Spot1 and Spot2 - Vector vecApex;// highest point - Vector vecScale; - Vector vecGrenadeVel; - Vector vecTemp; - float flGravity = g_psv_gravity->value * flGravityAdj; - - if (vecSpot2.z - vecSpot1.z > 500) - { - // to high, fail - return g_vecZero; - } - - UTIL_MakeVectors (pev->angles); - - // toss a little bit to the left or right, not right down on the enemy's bean (head). - vecSpot2 = vecSpot2 + gpGlobals->v_right * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - vecSpot2 = vecSpot2 + gpGlobals->v_forward * ( RANDOM_FLOAT(-8,8) + RANDOM_FLOAT(-16,16) ); - - // calculate the midpoint and apex of the 'triangle' - // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT - - // How much time does it take to get there? - - // get a rough idea of how high it can be thrown - vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,500), ignore_monsters, ENT(pev), &tr); - vecMidPoint = tr.vecEndPos; - // (subtract 15 so the grenade doesn't hit the ceiling) - vecMidPoint.z -= 15; - - if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z) - { - // to not enough space, fail - return g_vecZero; - } - - // How high should the grenade travel to reach the apex - float distance1 = (vecMidPoint.z - vecSpot1.z); - float distance2 = (vecMidPoint.z - vecSpot2.z); - - // How long will it take for the grenade to travel this distance - float time1 = sqrt( distance1 / (0.5 * flGravity) ); - float time2 = sqrt( distance2 / (0.5 * flGravity) ); - - if (time1 < 0.1) - { - // too close - return g_vecZero; - } - - // how hard to throw sideways to get there in time. - vecGrenadeVel = (vecSpot2 - vecSpot1) / (time1 + time2); - // how hard upwards to reach the apex at the right time. - vecGrenadeVel.z = flGravity * time1; - - // find the apex - vecApex = vecSpot1 + vecGrenadeVel * time1; - vecApex.z = vecMidPoint.z; - - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - // UNDONE: either ignore monsters or change it to not care if we hit our enemy - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - -// -// VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2. -// returns g_vecZero if throw is not feasible. -// -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj ) -{ - float flGravity = g_psv_gravity->value * flGravityAdj; - - Vector vecGrenadeVel = (vecSpot2 - vecSpot1); - - // throw at a constant time - float time = vecGrenadeVel.Length( ) / flSpeed; - vecGrenadeVel = vecGrenadeVel * (1.0 / time); - - // adjust upward toss to compensate for gravity loss - vecGrenadeVel.z += flGravity * time * 0.5; - - Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5; - vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5); - - TraceResult tr; - UTIL_TraceLine(vecSpot1, vecApex, dont_ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - UTIL_TraceLine(vecSpot2, vecApex, ignore_monsters, ENT(pev), &tr); - if (tr.flFraction != 1.0) - { - // fail! - return g_vecZero; - } - - return vecGrenadeVel; -} - - diff --git a/sdk/dlls/h_battery.cpp b/sdk/dlls/h_battery.cpp deleted file mode 100644 index 2b95fc7..0000000 --- a/sdk/dlls/h_battery.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_battery.cpp ======================================================== - - battery-related code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "skill.h" -#include "gamerules.h" - -class CRecharge : public CBaseToggle -{ -public: - void Spawn( ); - void Precache( void ); - void EXPORT Off(void); - void EXPORT Recharge(void); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flNextCharge; - int m_iReactivate ; // DeathMatch Delay until reactvated - int m_iJuice; - int m_iOn; // 0 = off, 1 = startup, 2 = going - float m_flSoundTime; -}; - -TYPEDESCRIPTION CRecharge::m_SaveData[] = -{ - DEFINE_FIELD( CRecharge, m_flNextCharge, FIELD_TIME ), - DEFINE_FIELD( CRecharge, m_iReactivate, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_iJuice, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_iOn, FIELD_INTEGER), - DEFINE_FIELD( CRecharge, m_flSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CRecharge, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_recharge, CRecharge); - - -void CRecharge::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "dmdelay")) - { - m_iReactivate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CRecharge::Spawn() -{ - Precache( ); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - m_iJuice = static_cast(gSkillData.suitchargerCapacity); - pev->frame = 0; -} - -void CRecharge::Precache() -{ - PRECACHE_SOUND("items/suitcharge1.wav"); - PRECACHE_SOUND("items/suitchargeno1.wav"); - PRECACHE_SOUND("items/suitchargeok1.wav"); -} - - -void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // if it's not a player, ignore - if (!FClassnameIs(pActivator->pev, "player")) - return; - - // if there is no juice left, turn it off - if (m_iJuice <= 0) - { - pev->frame = 1; - Off(); - } - - // if the player doesn't have the suit, or there is no juice left, make the deny noise - if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) - { - m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM ); - } - return; - } - - pev->nextthink = pev->ltime + 0.25; - SetThink(&CRecharge::Off); - - // Time to recharge yet? - - if (m_flNextCharge >= gpGlobals->time) - return; - - // Make sure that we have a caller - if (!pActivator) - return; - - m_hActivator = pActivator; - - //only recharge the player - - if (!m_hActivator->IsPlayer() ) - return; - - // Play the on sound or the looping charging sound - if (!m_iOn) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/suitchargeok1.wav", 0.85, ATTN_NORM ); - m_flSoundTime = 0.56 + gpGlobals->time; - } - if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/suitcharge1.wav", 0.85, ATTN_NORM ); - } - - - // charge the player - if (m_hActivator->pev->armorvalue < 100) - { - m_iJuice--; - m_hActivator->pev->armorvalue += 1; - - if (m_hActivator->pev->armorvalue > 100) - m_hActivator->pev->armorvalue = 100; - } - - // govern the rate of charge - m_flNextCharge = gpGlobals->time + 0.1; -} - -void CRecharge::Recharge(void) -{ - m_iJuice = static_cast(gSkillData.suitchargerCapacity); - pev->frame = 0; - SetThink( &CRecharge::SUB_DoNothing ); -} - -void CRecharge::Off(void) -{ - // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/suitcharge1.wav" ); - - m_iOn = 0; - - if ((!m_iJuice) && ( ( m_iReactivate = static_cast(g_pGameRules->FlHEVChargerRechargeTime()) ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink(&CRecharge::Recharge); - } - else - SetThink( &CRecharge::SUB_DoNothing ); -} diff --git a/sdk/dlls/h_cine.cpp b/sdk/dlls/h_cine.cpp deleted file mode 100644 index e087cb5..0000000 --- a/sdk/dlls/h_cine.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== h_cine.cpp ======================================================== - - The Halflife hard coded "scripted sequence". - - I'm pretty sure all this code is obsolete - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "decals.h" - - -class CLegacyCineMonster : public CBaseMonster -{ -public: - void CineSpawn( const char *szModel ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CineThink( void ); - void Pain( void ); - void Die( void ); -}; - -class CCineScientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-scientist.mdl"); } -}; -class CCine2Scientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2-scientist.mdl"); } -}; -class CCinePanther : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-panther.mdl"); } -}; - -class CCineBarney : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine-barney.mdl"); } -}; - -class CCine2HeavyWeapons : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2_hvyweapons.mdl"); } -}; - -class CCine2Slave : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine2_slave.mdl"); } -}; - -class CCine3Scientist : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine3-scientist.mdl"); } -}; - -class CCine3Barney : public CLegacyCineMonster -{ -public: - void Spawn( void ) { CineSpawn("models/cine3-barney.mdl"); } -}; - -// -// ********** Scientist SPAWN ********** -// - -LINK_ENTITY_TO_CLASS( monster_cine_scientist, CCineScientist ); -LINK_ENTITY_TO_CLASS( monster_cine_panther, CCinePanther ); -LINK_ENTITY_TO_CLASS( monster_cine_barney, CCineBarney ); -LINK_ENTITY_TO_CLASS( monster_cine2_scientist, CCine2Scientist ); -LINK_ENTITY_TO_CLASS( monster_cine2_hvyweapons, CCine2HeavyWeapons ); -LINK_ENTITY_TO_CLASS( monster_cine2_slave, CCine2Slave ); -LINK_ENTITY_TO_CLASS( monster_cine3_scientist, CCine3Scientist ); -LINK_ENTITY_TO_CLASS( monster_cine3_barney, CCine3Barney ); - -// -// ********** Scientist SPAWN ********** -// - -void CLegacyCineMonster :: CineSpawn( const char *szModel ) -{ - PRECACHE_MODEL(szModel); - SET_MODEL(ENT(pev), szModel); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 64)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 1; - pev->yaw_speed = 10; - - // ugly alpha hack, can't set ints from the bsp. - pev->sequence = (int)pev->impulse; - ResetSequenceInfo( ); - pev->framerate = 0.0; - - m_bloodColor = BLOOD_COLOR_RED; - - // if no targetname, start now - if ( FStringNull(pev->targetname) ) - { - SetThink( &CLegacyCineMonster::CineThink ); - pev->nextthink += 1.0; - } -} - - -// -// CineStart -// -void CLegacyCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->animtime = 0; // reset the sequence - SetThink( &CLegacyCineMonster::CineThink ); - pev->nextthink = gpGlobals->time; -} - -// -// ********** Scientist DIE ********** -// -void CLegacyCineMonster :: Die( void ) -{ - SetThink( &CLegacyCineMonster::SUB_Remove ); -} - -// -// ********** Scientist PAIN ********** -// -void CLegacyCineMonster :: Pain( void ) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pain3.wav", 1, ATTN_NORM); -} - -void CLegacyCineMonster :: CineThink( void ) -{ - // DBG_CheckMonsterData(pev); - - // Emit particles from origin (double check animator's placement of model) - // THIS is a test feature - //UTIL_ParticleEffect(pev->origin, g_vecZero, 255, 20); - - if (!pev->animtime) - ResetSequenceInfo( ); - - pev->nextthink = gpGlobals->time + 1.0; - - if (pev->spawnflags != 0 && m_fSequenceFinished) - { - Die(); - return; - } - - StudioFrameAdvance ( ); -} - -// -// cine_blood -// -// e3/prealpha only. -class CCineBlood : public CBaseEntity -{ -public: - void Spawn( void ); - void EXPORT BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT BloodGush ( void ); -}; - -LINK_ENTITY_TO_CLASS( cine_blood, CCineBlood ); - - -void CCineBlood :: BloodGush ( void ) -{ - Vector vecSplatDir; - TraceResult tr; - pev->nextthink = gpGlobals->time + 0.1; - - UTIL_MakeVectors(pev->angles); - if ( pev->health-- < 0 ) - REMOVE_ENTITY(ENT(pev)); -// CHANGE_METHOD ( ENT(pev), em_think, SUB_Remove ); - - if ( RANDOM_FLOAT ( 0 , 1 ) < 0.7 )// larger chance of globs - { - UTIL_BloodDrips( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, 10 ); - } - else// slim chance of geyser - { - UTIL_BloodStream( pev->origin, UTIL_RandomBloodVector(), BLOOD_COLOR_RED, RANDOM_LONG(50, 150) ); - } - - if ( RANDOM_FLOAT ( 0, 1 ) < 0.75 ) - {// decals the floor with blood. - vecSplatDir = Vector ( 0 , 0 , -1 ); - vecSplatDir = vecSplatDir + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_right) + (RANDOM_FLOAT(-1,1) * 0.6 * gpGlobals->v_forward);// randomize a bit - UTIL_TraceLine( pev->origin + Vector ( 0, 0 , 64) , pev->origin + vecSplatDir * 256, ignore_monsters, ENT(pev), &tr); - if ( tr.flFraction != 1.0 ) - { - // Decal with a bloodsplat - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - } -} - -void CCineBlood :: BloodStart ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CCineBlood::BloodGush ); - pev->nextthink = gpGlobals->time;// now! -} - -void CCineBlood :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; - SetUse ( &CCineBlood::BloodStart ); - pev->health = 20;//hacked health to count iterations -} - diff --git a/sdk/dlls/h_cycler.cpp b/sdk/dlls/h_cycler.cpp deleted file mode 100644 index e4ba59e..0000000 --- a/sdk/dlls/h_cycler.cpp +++ /dev/null @@ -1,471 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_cycler.cpp ======================================================== - - The Halflife Cycler Monsters - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "weapons.h" -#include "player.h" - - -#define TEMP_FOR_SCREEN_SHOTS -#ifdef TEMP_FOR_SCREEN_SHOTS //=================================================== - -class CCycler : public CBaseMonster -{ -public: - void GenericCyclerSpawn(const char *szModel, Vector vecMin, Vector vecMax); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_IMPULSE_USE); } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void Spawn( void ); - void Think( void ); - //void Pain( float flDamage ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // Don't treat as a live target - virtual BOOL IsAlive( void ) { return FALSE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - int m_animate; -}; - -TYPEDESCRIPTION CCycler::m_SaveData[] = -{ - DEFINE_FIELD( CCycler, m_animate, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CCycler, CBaseMonster ); - - -// -// we should get rid of all the other cyclers and replace them with this. -// -class CGenericCycler : public CCycler -{ -public: - void Spawn( void ) { GenericCyclerSpawn( (char *)STRING(pev->model), Vector(-16, -16, 0), Vector(16, 16, 72) ); } -}; -LINK_ENTITY_TO_CLASS( cycler, CGenericCycler ); - - - -// Probe droid imported for tech demo compatibility -// -// PROBE DROID -// -class CCyclerProbe : public CCycler -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( cycler_prdroid, CCyclerProbe ); -void CCyclerProbe :: Spawn( void ) -{ - pev->origin = pev->origin + Vector ( 0, 0, 16 ); - GenericCyclerSpawn( "models/prdroid.mdl", Vector(-16,-16,-16), Vector(16,16,16)); -} - - - -// Cycler member functions - -void CCycler :: GenericCyclerSpawn(const char *szModel, Vector vecMin, Vector vecMax) -{ - if (!szModel || !*szModel) - { - ALERT(at_error, "cycler at %.0f %.0f %0.f missing modelname", pev->origin.x, pev->origin.y, pev->origin.z ); - REMOVE_ENTITY(ENT(pev)); - return; - } - - pev->classname = MAKE_STRING("cycler"); - PRECACHE_MODEL( szModel ); - SET_MODEL(ENT(pev), szModel); - - CCycler::Spawn( ); - - UTIL_SetSize(pev, vecMin, vecMax); -} - - -void CCycler :: Spawn( ) -{ - InitBoneControllers(); - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_YES; - pev->effects = 0; - pev->health = 80000;// no cycler should die - pev->yaw_speed = 5; - pev->ideal_yaw = pev->angles.y; - ChangeYaw( 360 ); - - m_flFrameRate = 75; - m_flGroundSpeed = 0; - - pev->nextthink += 1.0; - - ResetSequenceInfo( ); - - if (pev->sequence != 0 || pev->frame != 0) - { - m_animate = 0; - pev->framerate = 0; - } - else - { - m_animate = 1; - } -} - - - - -// -// cycler think -// -void CCycler :: Think( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (m_animate) - { - StudioFrameAdvance ( ); - } - if (m_fSequenceFinished && !m_fSequenceLoops) - { - // ResetSequenceInfo(); - // hack to avoid reloading model every frame - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; - m_fSequenceFinished = FALSE; - m_flLastEventCheck = gpGlobals->time; - pev->frame = 0; - if (!m_animate) - pev->framerate = 0.0; // FIX: don't reset framerate - } -} - -// -// CyclerUse - starts a rotation trend -// -void CCycler :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_animate = !m_animate; - if (m_animate) - pev->framerate = 1.0; - else - pev->framerate = 0.0; -} - -// -// CyclerPain , changes sequences when shot -// -//void CCycler :: Pain( float flDamage ) -int CCycler :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (m_animate) - { - pev->sequence++; - - ResetSequenceInfo( ); - - if (m_flFrameRate == 0.0) - { - pev->sequence = 0; - ResetSequenceInfo( ); - } - pev->frame = 0; - } - else - { - pev->framerate = 1.0; - StudioFrameAdvance ( 0.1 ); - pev->framerate = 0; - ALERT( at_console, "sequence: %d, frame %.0f\n", pev->sequence, pev->frame ); - } - - return 0; -} - -#endif - - -class CCyclerSprite : public CBaseEntity -{ -public: - void Spawn( void ); - void Think( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() | FCAP_DONT_SAVE | FCAP_IMPULSE_USE); } - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void Animate( float frames ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline int ShouldAnimate( void ) { return m_animate && m_maxFrame > 1.0; } - int m_animate; - float m_lastTime; - float m_maxFrame; -}; - -LINK_ENTITY_TO_CLASS( cycler_sprite, CCyclerSprite ); - -TYPEDESCRIPTION CCyclerSprite::m_SaveData[] = -{ - DEFINE_FIELD( CCyclerSprite, m_animate, FIELD_INTEGER ), - DEFINE_FIELD( CCyclerSprite, m_lastTime, FIELD_TIME ), - DEFINE_FIELD( CCyclerSprite, m_maxFrame, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CCyclerSprite, CBaseEntity ); - - -void CCyclerSprite::Spawn( void ) -{ - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = DAMAGE_YES; - pev->effects = 0; - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - m_animate = 1; - m_lastTime = gpGlobals->time; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - - m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; -} - - -void CCyclerSprite::Think( void ) -{ - if ( ShouldAnimate() ) - Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); - - pev->nextthink = gpGlobals->time + 0.1; - m_lastTime = gpGlobals->time; -} - - -void CCyclerSprite::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_animate = !m_animate; - ALERT( at_console, "Sprite: %s\n", STRING(pev->model) ); -} - - -int CCyclerSprite::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( m_maxFrame > 1.0 ) - { - Animate( 1.0 ); - } - return 1; -} - -void CCyclerSprite::Animate( float frames ) -{ - pev->frame += frames; - if ( m_maxFrame > 0 ) - pev->frame = fmod( pev->frame, m_maxFrame ); -} - - - - - - - -class CWeaponCycler : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - int iItemSlot( void ) { return 1; } - int GetItemInfo(ItemInfo *p) {return 0; } - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - int m_iszModel; - int m_iModel; -}; -LINK_ENTITY_TO_CLASS( cycler_weapon, CWeaponCycler ); - - -void CWeaponCycler::Spawn( ) -{ - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_NONE; - - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - m_iszModel = pev->model; - m_iModel = pev->modelindex; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch( &CWeaponCycler::DefaultTouch ); -} - - - -BOOL CWeaponCycler::Deploy( ) -{ - m_pPlayer->pev->viewmodel = m_iszModel; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - SendWeaponAnim( 0 ); - m_iClip = 0; - return TRUE; -} - - -void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; -} - - -void CWeaponCycler::PrimaryAttack() -{ - - SendWeaponAnim( pev->sequence ); - - m_flNextPrimaryAttack = gpGlobals->time + 0.3; -} - - -void CWeaponCycler::SecondaryAttack( void ) -{ - float flFrameRate, flGroundSpeed; - - pev->sequence = (pev->sequence + 1) % 8; - - pev->modelindex = m_iModel; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - GetSequenceInfo( pmodel, pev, &flFrameRate, &flGroundSpeed ); - pev->modelindex = 0; - - if (flFrameRate == 0.0) - { - pev->sequence = 0; - } - - SendWeaponAnim( pev->sequence ); - - m_flNextSecondaryAttack = gpGlobals->time + 0.3; -} - - - -// Flaming Wreakage -class CWreckage : public CBaseMonster -{ - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - void Think( void ); - - int m_flStartTime; -}; -TYPEDESCRIPTION CWreckage::m_SaveData[] = -{ - DEFINE_FIELD( CWreckage, m_flStartTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CWreckage, CBaseMonster ); - - -LINK_ENTITY_TO_CLASS( cycler_wreckage, CWreckage ); - -void CWreckage::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->takedamage = 0; - pev->effects = 0; - - pev->frame = 0; - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->model) - { - PRECACHE_MODEL( (char *)STRING(pev->model) ); - SET_MODEL( ENT(pev), STRING(pev->model) ); - } - // pev->scale = 5.0; - - m_flStartTime = static_cast(gpGlobals->time); -} - -void CWreckage::Precache( ) -{ - if ( pev->model ) - PRECACHE_MODEL( (char *)STRING(pev->model) ); -} - -void CWreckage::Think( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.2; - - if (pev->dmgtime) - { - if (pev->dmgtime < gpGlobals->time) - { - UTIL_Remove( this ); - return; - } - else if (RANDOM_FLOAT( 0, pev->dmgtime - m_flStartTime ) > pev->dmgtime - gpGlobals->time) - { - return; - } - } - - Vector VecSrc; - - VecSrc.x = RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ); - VecSrc.y = RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ); - VecSrc.z = RANDOM_FLOAT( pev->absmin.z, pev->absmax.z ); - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, VecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( VecSrc.x ); - WRITE_COORD( VecSrc.y ); - WRITE_COORD( VecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,49) + 50 ); // scale * 10 - WRITE_BYTE( RANDOM_LONG(0, 3) + 8 ); // framerate - MESSAGE_END(); -} diff --git a/sdk/dlls/h_export.cpp b/sdk/dlls/h_export.cpp deleted file mode 100644 index 8b220a8..0000000 --- a/sdk/dlls/h_export.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== h_export.cpp ======================================================== - - Entity classes exported by Halflife. - -*/ - -#include "extdll.h" -#include "util.h" - -#include "cbase.h" - -// Holds engine functionality callbacks -enginefuncs_t g_engfuncs; -globalvars_t *gpGlobals; - -#undef DLLEXPORT -#ifdef _WIN32 -#define DLLEXPORT __stdcall -#else -#define DLLEXPORT __attribute__ ((visibility("default"))) -#endif - -#ifdef _WIN32 - -// Required DLL entry point -BOOL WINAPI DllMain( - HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - } - return TRUE; -} -#endif - -extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) -{ - memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); - gpGlobals = pGlobals; -} - - diff --git a/sdk/dlls/handgrenade.cpp b/sdk/dlls/handgrenade.cpp deleted file mode 100644 index 293cb78..0000000 --- a/sdk/dlls/handgrenade.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - - -#define HANDGRENADE_PRIMARY_VOLUME 450 - -enum handgrenade_e { - HANDGRENADE_IDLE = 0, - HANDGRENADE_FIDGET, - HANDGRENADE_PINPULL, - HANDGRENADE_THROW1, // toss - HANDGRENADE_THROW2, // medium - HANDGRENADE_THROW3, // hard - HANDGRENADE_HOLSTER, - HANDGRENADE_DRAW -}; - - -LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade ); - - -void CHandGrenade::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_HANDGRENADE; - SET_MODEL(ENT(pev), "models/w_grenade.mdl"); - -#ifndef CLIENT_DLL - pev->dmg = gSkillData.plrDmgHandGrenade; -#endif - - m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CHandGrenade::Precache( void ) -{ - PRECACHE_MODEL("models/w_grenade.mdl"); - PRECACHE_MODEL("models/v_grenade.mdl"); - PRECACHE_MODEL("models/p_grenade.mdl"); -} - -int CHandGrenade::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Hand Grenade"; - p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 0; - p->iId = m_iId = WEAPON_HANDGRENADE; - p->iWeight = HANDGRENADE_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - - -BOOL CHandGrenade::Deploy( ) -{ - m_flReleaseThrow = -1; - return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" ); -} - -BOOL CHandGrenade::CanHolster( void ) -{ - // can only holster hand grenades when not primed! - return ( m_flStartThrow == 0 ); -} - -void CHandGrenade::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - SendWeaponAnim( HANDGRENADE_HOLSTER ); - } - else - { - // no more grenades! - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - } - - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); -} - -void CHandGrenade::PrimaryAttack() -{ - if ( !m_flStartThrow && m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] > 0 ) - { - m_flStartThrow = gpGlobals->time; - m_flReleaseThrow = 0; - - SendWeaponAnim( HANDGRENADE_PINPULL ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } -} - - -void CHandGrenade::WeaponIdle( void ) -{ - if ( m_flReleaseThrow == 0 && m_flStartThrow ) - m_flReleaseThrow = gpGlobals->time; - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_flStartThrow ) - { - Vector angThrow = m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle; - - if ( angThrow.x < 0 ) - angThrow.x = -10 + angThrow.x * ( ( 90 - 10 ) / 90.0 ); - else - angThrow.x = -10 + angThrow.x * ( ( 90 + 10 ) / 90.0 ); - - float flVel = ( 90 - angThrow.x ) * 4; - if ( flVel > 500 ) - flVel = 500; - - UTIL_MakeVectors( angThrow ); - - Vector vecSrc = m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16; - - Vector vecThrow = gpGlobals->v_forward * flVel + m_pPlayer->pev->velocity; - - // alway explode 3 seconds after the pin was pulled - float time = m_flStartThrow - gpGlobals->time + 3.0; - if (time < 0) - time = 0; - - CGrenade::ShootTimed( m_pPlayer->pev, vecSrc, vecThrow, time ); - - if ( flVel < 500 ) - { - SendWeaponAnim( HANDGRENADE_THROW1 ); - } - else if ( flVel < 1000 ) - { - SendWeaponAnim( HANDGRENADE_THROW2 ); - } - else - { - SendWeaponAnim( HANDGRENADE_THROW3 ); - } - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flReleaseThrow = 0; - m_flStartThrow = 0; - m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - - m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ]--; - - if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - // just threw last grenade - // set attack times in the future, and weapon idle in the future so we can see the whole throw - // animation, weapon idle will automatically retire the weapon for us. - m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay(0.5);// ensure that the animation can finish playing - } - return; - } - else if ( m_flReleaseThrow > 0 ) - { - // we've finished the throw, restart. - m_flStartThrow = 0; - - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - SendWeaponAnim( HANDGRENADE_DRAW ); - } - else - { - RetireWeapon(); - return; - } - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - m_flReleaseThrow = -1; - return; - } - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = HANDGRENADE_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. - } - else - { - iAnim = HANDGRENADE_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0; - } - - SendWeaponAnim( iAnim ); - } -} - - - - diff --git a/sdk/dlls/hassassin.cpp b/sdk/dlls/hassassin.cpp deleted file mode 100644 index feaeb23..0000000 --- a/sdk/dlls/hassassin.cpp +++ /dev/null @@ -1,1017 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// hassassin - Human assassin, fast and stealthy -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "squadmonster.h" -#include "weapons.h" -#include "soundent.h" -#include "game.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_ASSASSIN_EXPOSED = LAST_COMMON_SCHEDULE + 1,// cover was blown. - SCHED_ASSASSIN_JUMP, // fly through the air - SCHED_ASSASSIN_JUMP_ATTACK, // fly through the air and shoot - SCHED_ASSASSIN_JUMP_LAND, // hit and run away -}; - -//========================================================= -// monster-specific tasks -//========================================================= - -enum -{ - TASK_ASSASSIN_FALL_TO_GROUND = LAST_COMMON_TASK + 1, // falling and waiting to hit ground -}; - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ASSASSIN_AE_SHOOT1 1 -#define ASSASSIN_AE_TOSS1 2 -#define ASSASSIN_AE_JUMP 3 - - -#define bits_MEMORY_BADJUMP (bits_MEMORY_CUSTOM1) - -class CHAssassin : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void); - void Shoot( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - Schedule_t* GetSchedule ( void ); - Schedule_t* GetScheduleOfType ( int Type ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); // jump - // BOOL CheckMeleeAttack2 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); // shoot - BOOL CheckRangeAttack2 ( float flDot, float flDist ); // throw grenade - void StartTask ( Task_t *pTask ); - void RunAI( void ); - void RunTask ( Task_t *pTask ); - void DeathSound ( void ); - void IdleSound ( void ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flLastShot; - float m_flDiviation; - - float m_flNextJump; - Vector m_vecJumpVelocity; - - float m_flNextGrenadeCheck; - Vector m_vecTossVelocity; - BOOL m_fThrowGrenade; - - int m_iTargetRanderamt; - - int m_iFrustration; - - int m_iShell; -}; -LINK_ENTITY_TO_CLASS( monster_human_assassin, CHAssassin ); - - -TYPEDESCRIPTION CHAssassin::m_SaveData[] = -{ - DEFINE_FIELD( CHAssassin, m_flLastShot, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_flDiviation, FIELD_FLOAT ), - - DEFINE_FIELD( CHAssassin, m_flNextJump, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecJumpVelocity, FIELD_VECTOR ), - - DEFINE_FIELD( CHAssassin, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHAssassin, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHAssassin, m_fThrowGrenade, FIELD_BOOLEAN ), - - DEFINE_FIELD( CHAssassin, m_iTargetRanderamt, FIELD_INTEGER ), - DEFINE_FIELD( CHAssassin, m_iFrustration, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHAssassin, CBaseMonster ); - - -//========================================================= -// DieSound -//========================================================= -void CHAssassin :: DeathSound ( void ) -{ -} - -//========================================================= -// IdleSound -//========================================================= -void CHAssassin :: IdleSound ( void ) -{ -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CHAssassin :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHAssassin :: Classify ( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHAssassin :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 360; - break; - default: - ys = 360; - break; - } - - pev->yaw_speed = ys; -} - - -//========================================================= -// Shoot -//========================================================= -void CHAssassin :: Shoot ( void ) -{ - if (m_hEnemy == 0) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - if (m_flLastShot + 2 < gpGlobals->time) - { - m_flDiviation = 0.10; - } - else - { - m_flDiviation -= 0.01; - if (m_flDiviation < 0.02) - m_flDiviation = 0.02; - } - m_flLastShot = gpGlobals->time; - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( pev->origin + gpGlobals->v_up * 32 + gpGlobals->v_forward * 12, vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL); - FireBullets(1, vecShootOrigin, vecShootDir, Vector( m_flDiviation, m_flDiviation, m_flDiviation ), 2048, BULLET_MONSTER_9MM ); // shoot +-8 degrees - - switch(RANDOM_LONG(0,1)) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.6, 0.8), ATTN_NORM); - break; - } - - pev->effects |= EF_MUZZLEFLASH; - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); - - m_cAmmoLoaded--; -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CHAssassin :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ASSASSIN_AE_SHOOT1: - Shoot( ); - break; - case ASSASSIN_AE_TOSS1: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 2.0 ); - - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - m_fThrowGrenade = FALSE; - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - case ASSASSIN_AE_JUMP: - { - // ALERT( at_console, "jumping"); - UTIL_MakeAimVectors( pev->angles ); - pev->movetype = MOVETYPE_TOSS; - pev->flags &= ~FL_ONGROUND; - pev->velocity = m_vecJumpVelocity; - m_flNextJump = gpGlobals->time + 3.0; - } - return; - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHAssassin :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/hassassin.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hassassinHealth; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_MELEE_ATTACK1 | bits_CAP_DOORS_GROUP; - pev->friction = 1; - - m_HackedGunPos = Vector( 0, 24, 48 ); - - m_iTargetRanderamt = 20; - pev->renderamt = 20; - pev->rendermode = kRenderTransTexture; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHAssassin :: Precache() -{ - PRECACHE_MODEL("models/hassassin.mdl"); - - PRECACHE_SOUND("weapons/pl_gun1.wav"); - PRECACHE_SOUND("weapons/pl_gun2.wav"); - - PRECACHE_SOUND("debris/beamstart1.wav"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell -} - - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// Fail Schedule -//========================================================= -Task_t tlAssassinFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - // { TASK_WAIT_PVS, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinFail[] = -{ - { - tlAssassinFail, - ARRAYSIZE ( tlAssassinFail ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - "AssassinFail" - }, -}; - - -//========================================================= -// Enemy exposed Agrunt's cover -//========================================================= -Task_t tlAssassinExposed[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slAssassinExposed[] = -{ - { - tlAssassinExposed, - ARRAYSIZE ( tlAssassinExposed ), - bits_COND_CAN_MELEE_ATTACK1, - 0, - "AssassinExposed", - }, -}; - - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy[] = -{ - { - tlAssassinTakeCoverFromEnemy, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy" - }, -}; - - -//========================================================= -// Take cover from enemy! Tries lateral cover before node -// cover! -//========================================================= -Task_t tlAssassinTakeCoverFromEnemy2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_WAIT, (float)0.2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK2 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, -}; - -Schedule_t slAssassinTakeCoverFromEnemy2[] = -{ - { - tlAssassinTakeCoverFromEnemy2, - ARRAYSIZE ( tlAssassinTakeCoverFromEnemy2 ), - bits_COND_NEW_ENEMY | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinTakeCoverFromEnemy2" - }, -}; - - -//========================================================= -// hide from the loudest sound source -//========================================================= -Task_t tlAssassinTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slAssassinTakeCoverFromBestSound[] = -{ - { - tlAssassinTakeCoverFromBestSound, - ARRAYSIZE ( tlAssassinTakeCoverFromBestSound ), - bits_COND_NEW_ENEMY, - 0, - "AssassinTakeCoverFromBestSound" - }, -}; - - - - - -//========================================================= -// AlertIdle Schedules -//========================================================= -Task_t tlAssassinHide[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_SET_SCHEDULE, (float)SCHED_CHASE_ENEMY }, -}; - -Schedule_t slAssassinHide[] = -{ - { - tlAssassinHide, - ARRAYSIZE ( tlAssassinHide ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_FEAR | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinHide" - }, -}; - - - -//========================================================= -// HUNT Schedules -//========================================================= -Task_t tlAssassinHunt[] = -{ - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slAssassinHunt[] = -{ - { - tlAssassinHunt, - ARRAYSIZE ( tlAssassinHunt ), - bits_COND_NEW_ENEMY | - // bits_COND_SEE_ENEMY | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "AssassinHunt" - }, -}; - - -//========================================================= -// Jumping Schedules -//========================================================= -Task_t tlAssassinJump[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_SET_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_ATTACK }, -}; - -Schedule_t slAssassinJump[] = -{ - { - tlAssassinJump, - ARRAYSIZE ( tlAssassinJump ), - 0, - 0, - "AssassinJump" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpAttack[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_JUMP_LAND }, - // { TASK_SET_ACTIVITY, (float)ACT_FLY }, - { TASK_ASSASSIN_FALL_TO_GROUND, (float)0 }, -}; - - -Schedule_t slAssassinJumpAttack[] = -{ - { - tlAssassinJumpAttack, - ARRAYSIZE ( tlAssassinJumpAttack ), - 0, - 0, - "AssassinJumpAttack" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlAssassinJumpLand[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_ASSASSIN_EXPOSED }, - // { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MELEE_ATTACK1 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_REMEMBER, (float)bits_MEMORY_BADJUMP }, - { TASK_FIND_NODE_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_FORGET, (float)bits_MEMORY_BADJUMP }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RANGE_ATTACK1 }, -}; - -Schedule_t slAssassinJumpLand[] = -{ - { - tlAssassinJumpLand, - ARRAYSIZE ( tlAssassinJumpLand ), - 0, - 0, - "AssassinJumpLand" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHAssassin ) -{ - slAssassinFail, - slAssassinExposed, - slAssassinTakeCoverFromEnemy, - slAssassinTakeCoverFromEnemy2, - slAssassinTakeCoverFromBestSound, - slAssassinHide, - slAssassinHunt, - slAssassinJump, - slAssassinJumpAttack, - slAssassinJumpLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHAssassin, CBaseMonster ); - - -//========================================================= -// CheckMeleeAttack1 - jump like crazy if the enemy gets too close. -//========================================================= -BOOL CHAssassin :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( m_flNextJump < gpGlobals->time && (flDist <= 128 || HasMemory( bits_MEMORY_BADJUMP )) && m_hEnemy != 0 ) - { - TraceResult tr; - - Vector vecDest = pev->origin + Vector( RANDOM_FLOAT( -64, 64), RANDOM_FLOAT( -64, 64 ), 160 ); - - UTIL_TraceHull( pev->origin + Vector( 0, 0, 36 ), vecDest + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, ENT(pev), &tr); - - if ( tr.fStartSolid || tr.flFraction < 1.0) - { - return FALSE; - } - - float flGravity = g_psv_gravity->value; - - float time = sqrt( 160 / (0.5 * flGravity)); - float speed = flGravity * time / 160; - m_vecJumpVelocity = (vecDest - pev->origin) * speed; - - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - drop a cap in their ass -// -//========================================================= -BOOL CHAssassin :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist > 64 && flDist <= 2048 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - TraceResult tr; - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), dont_ignore_monsters, ENT(pev), &tr); - - if ( tr.flFraction == 1 || tr.pHit == m_hEnemy->edict() ) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - toss grenade is enemy gets in the way and is too close. -//========================================================= -BOOL CHAssassin :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - m_fThrowGrenade = FALSE; - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) - { - // don't throw grenades at anything that isn't on the ground! - return FALSE; - } - - // don't get grenade happy unless the player starts to piss you off - if ( m_iFrustration <= 2) - return FALSE; - - if ( m_flNextGrenadeCheck < gpGlobals->time && !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 512 /* && flDot >= 0.5 */ /* && NoFriendlyFire() */ ) - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition( ), m_hEnemy->Center(), flDist, 0.5 ); // use dist as speed to get there in 1 second - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - - return TRUE; - } - } - - return FALSE; -} - - -//========================================================= -// RunAI -//========================================================= -void CHAssassin :: RunAI( void ) -{ - CBaseMonster :: RunAI(); - - // always visible if moving - // always visible is not on hard - if (g_iSkillLevel != SKILL_HARD || m_hEnemy == 0 || pev->deadflag != DEAD_NO || m_Activity == ACT_RUN || m_Activity == ACT_WALK || !(pev->flags & FL_ONGROUND)) - m_iTargetRanderamt = 255; - else - m_iTargetRanderamt = 20; - - if (pev->renderamt > m_iTargetRanderamt) - { - if (pev->renderamt == 255) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "debris/beamstart1.wav", 0.2, ATTN_NORM ); - } - - pev->renderamt = max( pev->renderamt - 50, m_iTargetRanderamt ); - pev->rendermode = kRenderTransTexture; - } - else if (pev->renderamt < m_iTargetRanderamt) - { - pev->renderamt = min( pev->renderamt + 50, m_iTargetRanderamt ); - if (pev->renderamt == 255) - pev->rendermode = kRenderNormal; - } - - if (m_Activity == ACT_RUN || m_Activity == ACT_WALK) - { - static int iStep = 0; - iStep = ! iStep; - if (iStep) - { - switch( RANDOM_LONG( 0, 3 ) ) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step1.wav", 0.5, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step3.wav", 0.5, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step2.wav", 0.5, ATTN_NORM); break; - case 3: EMIT_SOUND( ENT(pev), CHAN_BODY, "player/pl_step4.wav", 0.5, ATTN_NORM); break; - } - } - } -} - - -//========================================================= -// StartTask -//========================================================= -void CHAssassin :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK2: - if (!m_fThrowGrenade) - { - TaskComplete( ); - } - else - { - CBaseMonster :: StartTask ( pTask ); - } - break; - case TASK_ASSASSIN_FALL_TO_GROUND: - break; - default: - CBaseMonster :: StartTask ( pTask ); - break; - } -} - - -//========================================================= -// RunTask -//========================================================= -void CHAssassin :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ASSASSIN_FALL_TO_GROUND: - MakeIdealYaw( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if (m_fSequenceFinished) - { - if (pev->velocity.z > 0) - { - pev->sequence = LookupSequence( "fly_up" ); - } - else if (HasConditions ( bits_COND_SEE_ENEMY )) - { - pev->sequence = LookupSequence( "fly_attack" ); - pev->frame = 0; - } - else - { - pev->sequence = LookupSequence( "fly_down" ); - pev->frame = 0; - } - - ResetSequenceInfo( ); - SetYawSpeed(); - } - if (pev->flags & FL_ONGROUND) - { - // ALERT( at_console, "on ground\n"); - TaskComplete( ); - } - break; - default: - CBaseMonster :: RunTask ( pTask ); - break; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CHAssassin :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - { - if ( HasConditions ( bits_COND_HEAR_SOUND )) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - if ( pSound && (pSound->m_iType & bits_SOUND_COMBAT) ) - { - return GetScheduleOfType( SCHED_INVESTIGATE_SOUND ); - } - } - } - break; - - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - // flying? - if ( pev->movetype == MOVETYPE_TOSS) - { - if (pev->flags & FL_ONGROUND) - { - // ALERT( at_console, "landed\n"); - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_LAND ); - } - else - { - // ALERT( at_console, "jump\n"); - // jump or jump/shoot - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP ); - else - return GetScheduleOfType ( SCHED_ASSASSIN_JUMP_ATTACK ); - } - } - - if ( HasConditions ( bits_COND_HEAR_SOUND )) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - } - - if ( HasConditions ( bits_COND_LIGHT_DAMAGE ) ) - { - m_iFrustration++; - } - if ( HasConditions ( bits_COND_HEAVY_DAMAGE ) ) - { - m_iFrustration++; - } - - // jump player! - if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - // ALERT( at_console, "melee attack 1\n"); - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } - - // throw grenade - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) ) - { - // ALERT( at_console, "range attack 2\n"); - return GetScheduleOfType ( SCHED_RANGE_ATTACK2 ); - } - - // spotted - if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n"); - m_iFrustration++; - return GetScheduleOfType ( SCHED_ASSASSIN_EXPOSED ); - } - - // can attack - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - // ALERT( at_console, "range attack 1\n"); - m_iFrustration = 0; - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // ALERT( at_console, "face\n"); - return GetScheduleOfType ( SCHED_COMBAT_FACE ); - } - - // new enemy - if ( HasConditions ( bits_COND_NEW_ENEMY ) ) - { - // ALERT( at_console, "take cover\n"); - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - // ALERT( at_console, "stand\n"); - return GetScheduleOfType ( SCHED_ALERT_STAND ); - } - break; - default: - break; - } - - return CBaseMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CHAssassin :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "%d\n", m_iFrustration ); - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - if (pev->health > 30) - return slAssassinTakeCoverFromEnemy; - else - return slAssassinTakeCoverFromEnemy2; - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - return slAssassinTakeCoverFromBestSound; - case SCHED_ASSASSIN_EXPOSED: - return slAssassinExposed; - case SCHED_FAIL: - if (m_MonsterState == MONSTERSTATE_COMBAT) - return slAssassinFail; - break; - case SCHED_ALERT_STAND: - if (m_MonsterState == MONSTERSTATE_COMBAT) - return slAssassinHide; - break; - case SCHED_CHASE_ENEMY: - return slAssassinHunt; - case SCHED_MELEE_ATTACK1: - if (pev->flags & FL_ONGROUND) - { - if (m_flNextJump > gpGlobals->time) - { - // can't jump yet, go ahead and fail - return slAssassinFail; - } - else - { - return slAssassinJump; - } - } - else - { - return slAssassinJumpAttack; - } - case SCHED_ASSASSIN_JUMP: - case SCHED_ASSASSIN_JUMP_ATTACK: - return slAssassinJumpAttack; - case SCHED_ASSASSIN_JUMP_LAND: - return slAssassinJumpLand; - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - -#endif diff --git a/sdk/dlls/headcrab.cpp b/sdk/dlls/headcrab.cpp deleted file mode 100644 index 34954b8..0000000 --- a/sdk/dlls/headcrab.cpp +++ /dev/null @@ -1,555 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// headcrab.cpp - tiny, jumpy alien parasite -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "game.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HC_AE_JUMPATTACK ( 2 ) - -Task_t tlHCRangeAttack1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_WAIT_RANDOM, (float)0.5 }, -}; - -Schedule_t slHCRangeAttack1[] = -{ - { - tlHCRangeAttack1, - ARRAYSIZE ( tlHCRangeAttack1 ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRangeAttack1" - }, -}; - -Task_t tlHCRangeAttack1Fast[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slHCRangeAttack1Fast[] = -{ - { - tlHCRangeAttack1Fast, - ARRAYSIZE ( tlHCRangeAttack1Fast ), - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED, - 0, - "HCRAFast" - }, -}; - -class CHeadCrab : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void RunTask ( Task_t *pTask ); - void StartTask ( Task_t *pTask ); - void SetYawSpeed ( void ); - void EXPORT LeapTouch ( CBaseEntity *pOther ); - Vector Center( void ); - Vector BodyTarget( const Vector &posSrc ); - void PainSound( void ); - void DeathSound( void ); - void IdleSound( void ); - void AlertSound( void ); - void PrescheduleThink( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; } - virtual int GetVoicePitch( void ) { return 100; } - virtual float GetSoundVolue( void ) { return 1.0; } - Schedule_t* GetScheduleOfType ( int Type ); - - CUSTOM_SCHEDULES; - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackSounds[]; - static const char *pDeathSounds[]; - static const char *pBiteSounds[]; -}; -LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab ); - -DEFINE_CUSTOM_SCHEDULES( CHeadCrab ) -{ - slHCRangeAttack1, - slHCRangeAttack1Fast, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHeadCrab, CBaseMonster ); - -const char *CHeadCrab::pIdleSounds[] = -{ - "headcrab/hc_idle1.wav", - "headcrab/hc_idle2.wav", - "headcrab/hc_idle3.wav", -}; -const char *CHeadCrab::pAlertSounds[] = -{ - "headcrab/hc_alert1.wav", -}; -const char *CHeadCrab::pPainSounds[] = -{ - "headcrab/hc_pain1.wav", - "headcrab/hc_pain2.wav", - "headcrab/hc_pain3.wav", -}; -const char *CHeadCrab::pAttackSounds[] = -{ - "headcrab/hc_attack1.wav", - "headcrab/hc_attack2.wav", - "headcrab/hc_attack3.wav", -}; - -const char *CHeadCrab::pDeathSounds[] = -{ - "headcrab/hc_die1.wav", - "headcrab/hc_die2.wav", -}; - -const char *CHeadCrab::pBiteSounds[] = -{ - "headcrab/hc_headbite.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHeadCrab :: Classify ( void ) -{ - return CLASS_ALIEN_PREY; -} - -//========================================================= -// Center - returns the real center of the headcrab. The -// bounding box is much larger than the actual creature so -// this is needed for targeting -//========================================================= -Vector CHeadCrab :: Center ( void ) -{ - return Vector( pev->origin.x, pev->origin.y, pev->origin.z + 6 ); -} - - -Vector CHeadCrab :: BodyTarget( const Vector &posSrc ) -{ - return Center( ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHeadCrab :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 30; - break; - case ACT_RUN: - case ACT_WALK: - ys = 20; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 60; - break; - case ACT_RANGE_ATTACK1: - ys = 30; - break; - default: - ys = 30; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHeadCrab :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case HC_AE_JUMPATTACK: - { - ClearBits( pev->flags, FL_ONGROUND ); - - UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground - UTIL_MakeVectors ( pev->angles ); - - Vector vecJumpDir; - if (m_hEnemy != 0) - { - float gravity = g_psv_gravity->value; - if (gravity <= 1) - gravity = 1; - - // How fast does the headcrab need to travel to reach that height given gravity? - float height = (m_hEnemy->pev->origin.z + m_hEnemy->pev->view_ofs.z - pev->origin.z); - if (height < 16) - height = 16; - float speed = sqrt( 2 * gravity * height ); - float time = speed / gravity; - - // Scale the sideways velocity to get there at the right time - vecJumpDir = (m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin); - vecJumpDir = vecJumpDir * ( 1.0 / time ); - - // Speed to offset gravity at the desired height - vecJumpDir.z = speed; - - // Don't jump too far/fast - float distance = vecJumpDir.Length(); - - if (distance > 650) - { - vecJumpDir = vecJumpDir * ( 650.0 / distance ); - } - } - else - { - // jump hop, don't care where - vecJumpDir = Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_up.z ) * 350; - } - - int iSound = RANDOM_LONG(0,2); - if ( iSound != 0 ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[iSound], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pev->velocity = vecJumpDir; - m_flNextAttack = gpGlobals->time + 2; - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHeadCrab :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/headcrab.mdl"); - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.headcrabHealth; - pev->view_ofs = Vector ( 0, 0, 20 );// position of the eyes relative to monster's origin. - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHeadCrab :: Precache() -{ - PRECACHE_SOUND_ARRAY(pIdleSounds); - PRECACHE_SOUND_ARRAY(pAlertSounds); - PRECACHE_SOUND_ARRAY(pPainSounds); - PRECACHE_SOUND_ARRAY(pAttackSounds); - PRECACHE_SOUND_ARRAY(pDeathSounds); - PRECACHE_SOUND_ARRAY(pBiteSounds); - - PRECACHE_MODEL("models/headcrab.mdl"); -} - - -//========================================================= -// RunTask -//========================================================= -void CHeadCrab :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - case TASK_RANGE_ATTACK2: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - SetTouch( NULL ); - m_IdealActivity = ACT_IDLE; - } - break; - } - default: - { - CBaseMonster :: RunTask(pTask); - } - } -} - -//========================================================= -// LeapTouch - this is the headcrab's touch function when it -// is in the air -//========================================================= -void CHeadCrab :: LeapTouch ( CBaseEntity *pOther ) -{ - if ( !pOther->pev->takedamage ) - { - return; - } - - if ( pOther->Classify() == Classify() ) - { - return; - } - - // Don't hit if back on ground - if ( !FBitSet( pev->flags, FL_ONGROUND ) ) - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pBiteSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - - pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH ); - } - - SetTouch( NULL ); -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHeadCrab :: PrescheduleThink ( void ) -{ - // make the crab coo a little bit in combat state - if ( m_MonsterState == MONSTERSTATE_COMBAT && RANDOM_FLOAT( 0, 5 ) < 0.1 ) - { - IdleSound(); - } -} - -void CHeadCrab :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_RANGE_ATTACK1: - { - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); - m_IdealActivity = ACT_RANGE_ATTACK1; - SetTouch ( &CHeadCrab::LeapTouch ); - break; - } - default: - { - CBaseMonster :: StartTask( pTask ); - } - } -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist <= 256 && flDot >= 0.65 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CHeadCrab :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - return FALSE; - // BUGBUG: Why is this code here? There is no ACT_RANGE_ATTACK2 animation. I've disabled it for now. -#if 0 - if ( FBitSet( pev->flags, FL_ONGROUND ) && flDist > 64 && flDist <= 256 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -#endif -} - -int CHeadCrab :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Don't take any acid damage -- BigMomma's mortar is acid - if ( bitsDamageType & DMG_ACID ) - flDamage = 0; - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// IdleSound -//========================================================= -#define CRAB_ATTN_IDLE (float)1.5 -void CHeadCrab :: IdleSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: AlertSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// AlertSound -//========================================================= -void CHeadCrab :: PainSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -//========================================================= -// DeathSound -//========================================================= -void CHeadCrab :: DeathSound ( void ) -{ - EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() ); -} - -Schedule_t* CHeadCrab :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_RANGE_ATTACK1: - { - return &slHCRangeAttack1[ 0 ]; - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - - -class CBabyCrab : public CHeadCrab -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite * 0.3; } - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - Schedule_t* GetScheduleOfType ( int Type ); - virtual int GetVoicePitch( void ) { return PITCH_NORM + RANDOM_LONG(40,50); } - virtual float GetSoundVolue( void ) { return 0.8; } -}; -LINK_ENTITY_TO_CLASS( monster_babycrab, CBabyCrab ); - -void CBabyCrab :: Spawn( void ) -{ - CHeadCrab::Spawn(); - SET_MODEL(ENT(pev), "models/baby_headcrab.mdl"); - pev->rendermode = kRenderTransTexture; - pev->renderamt = 192; - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - - pev->health = gSkillData.headcrabHealth * 0.25; // less health than full grown -} - -void CBabyCrab :: Precache( void ) -{ - PRECACHE_MODEL( "models/baby_headcrab.mdl" ); - CHeadCrab::Precache(); -} - - -void CBabyCrab :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 120; -} - - -BOOL CBabyCrab :: CheckRangeAttack1( float flDot, float flDist ) -{ - if ( pev->flags & FL_ONGROUND ) - { - if ( pev->groundentity && (pev->groundentity->v.flags & (FL_CLIENT|FL_MONSTER)) ) - return TRUE; - - // A little less accurate, but jump from closer - if ( flDist <= 180 && flDot >= 0.55 ) - return TRUE; - } - - return FALSE; -} - - -Schedule_t* CBabyCrab :: GetScheduleOfType ( int Type ) -{ - switch( Type ) - { - case SCHED_FAIL: // If you fail, try to jump! - if ( m_hEnemy != 0 ) - return slHCRangeAttack1Fast; - break; - - case SCHED_RANGE_ATTACK1: - { - return slHCRangeAttack1Fast; - } - break; - } - - return CHeadCrab::GetScheduleOfType( Type ); -} diff --git a/sdk/dlls/healthkit.cpp b/sdk/dlls/healthkit.cpp deleted file mode 100644 index 5245564..0000000 --- a/sdk/dlls/healthkit.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "items.h" -#include "gamerules.h" - -extern int gmsgItemPickup; - -class CHealthKit : public CItem -{ - void Spawn( void ); - void Precache( void ); - BOOL MyTouch( CBasePlayer *pPlayer ); - -/* - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; -*/ - -}; - - -LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); - -/* -TYPEDESCRIPTION CHealthKit::m_SaveData[] = -{ - -}; - - -IMPLEMENT_SAVERESTORE( CHealthKit, CItem); -*/ - -void CHealthKit :: Spawn( void ) -{ - Precache( ); - SET_MODEL(ENT(pev), "models/w_medkit.mdl"); - - CItem::Spawn(); -} - -void CHealthKit::Precache( void ) -{ - PRECACHE_MODEL("models/w_medkit.mdl"); - PRECACHE_SOUND("items/smallmedkit1.wav"); -} - -BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer ) -{ - if ( pPlayer->pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - if ( pPlayer->TakeHealth( gSkillData.healthkitCapacity, DMG_GENERIC ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM); - - if ( g_pGameRules->ItemShouldRespawn( this ) ) - { - Respawn(); - } - else - { - UTIL_Remove(this); - } - - return TRUE; - } - - return FALSE; -} - - - -//------------------------------------------------------------- -// Wall mounted health kit -//------------------------------------------------------------- -class CWallHealth : public CBaseToggle -{ -public: - void Spawn( ); - void Precache( void ); - void EXPORT Off(void); - void EXPORT Recharge(void); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() | FCAP_CONTINUOUS_USE) & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - float m_flNextCharge; - int m_iReactivate ; // DeathMatch Delay until reactvated - int m_iJuice; - int m_iOn; // 0 = off, 1 = startup, 2 = going - float m_flSoundTime; -}; - -TYPEDESCRIPTION CWallHealth::m_SaveData[] = -{ - DEFINE_FIELD( CWallHealth, m_flNextCharge, FIELD_TIME), - DEFINE_FIELD( CWallHealth, m_iReactivate, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_iJuice, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_iOn, FIELD_INTEGER), - DEFINE_FIELD( CWallHealth, m_flSoundTime, FIELD_TIME), -}; - -IMPLEMENT_SAVERESTORE( CWallHealth, CBaseEntity ); - -LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth); - - -void CWallHealth::KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - { - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "dmdelay")) - { - m_iReactivate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -void CWallHealth::Spawn() -{ - Precache( ); - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - m_iJuice = static_cast(gSkillData.healthchargerCapacity); - pev->frame = 0; - -} - -void CWallHealth::Precache() -{ - PRECACHE_SOUND("items/medshot4.wav"); - PRECACHE_SOUND("items/medshotno1.wav"); - PRECACHE_SOUND("items/medcharge4.wav"); -} - - -void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Make sure that we have a caller - if (!pActivator) - return; - // if it's not a player, ignore - if ( !pActivator->IsPlayer() ) - return; - - // if there is no juice left, turn it off - if (m_iJuice <= 0) - { - pev->frame = 1; - Off(); - } - - // if the player doesn't have the suit, or there is no juice left, make the deny noise - if ((m_iJuice <= 0) || (!(pActivator->pev->weapons & (1<time) - { - m_flSoundTime = gpGlobals->time + 0.62; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshotno1.wav", 1.0, ATTN_NORM ); - } - return; - } - - pev->nextthink = pev->ltime + 0.25; - SetThink(&CWallHealth::Off); - - // Time to recharge yet? - - if (m_flNextCharge >= gpGlobals->time) - return; - - // Play the on sound or the looping charging sound - if (!m_iOn) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); - m_flSoundTime = 0.56 + gpGlobals->time; - } - if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->time)) - { - m_iOn++; - EMIT_SOUND(ENT(pev), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM ); - } - - - // charge the player - if ( pActivator->TakeHealth( 1, DMG_GENERIC ) ) - { - m_iJuice--; - } - - // govern the rate of charge - m_flNextCharge = gpGlobals->time + 0.1; -} - -void CWallHealth::Recharge(void) -{ - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/medshot4.wav", 1.0, ATTN_NORM ); - m_iJuice = static_cast(gSkillData.healthchargerCapacity); - pev->frame = 0; - SetThink( &CWallHealth::SUB_DoNothing ); -} - -void CWallHealth::Off(void) -{ - // Stop looping sound. - if (m_iOn > 1) - STOP_SOUND( ENT(pev), CHAN_STATIC, "items/medcharge4.wav" ); - - m_iOn = 0; - - if ((!m_iJuice) && ( ( m_iReactivate = static_cast(g_pGameRules->FlHealthChargerRechargeTime()) ) > 0) ) - { - pev->nextthink = pev->ltime + m_iReactivate; - SetThink(&CWallHealth::Recharge); - } - else - SetThink( &CWallHealth::SUB_DoNothing ); -} diff --git a/sdk/dlls/hgrunt.cpp b/sdk/dlls/hgrunt.cpp deleted file mode 100644 index 51e9817..0000000 --- a/sdk/dlls/hgrunt.cpp +++ /dev/null @@ -1,2518 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// hgrunt -//========================================================= - -//========================================================= -// Hit groups! -//========================================================= -/* - - 1 - Head - 2 - Stomach - 3 - Gun - -*/ - - -#include "extdll.h" -#include "plane.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "squadmonster.h" -#include "weapons.h" -#include "talkmonster.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers. - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// monster-specific DEFINE's -//========================================================= -#define GRUNT_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! -#define GRUNT_VOL 0.35 // volume of grunt sounds -#define GRUNT_ATTN ATTN_NORM // attenutation of grunt sentences -#define HGRUNT_LIMP_HEALTH 20 -#define HGRUNT_DMG_HEADSHOT ( DMG_BULLET | DMG_CLUB ) // damage types that can kill a grunt with a single headshot. -#define HGRUNT_NUM_HEADS 2 // how many grunt heads are there? -#define HGRUNT_MINIMUM_HEADSHOT_DAMAGE 15 // must do at least this much damage in one shot to head to score a headshot kill -#define HGRUNT_SENTENCE_VOLUME (float)0.35 // volume of grunt sentences - -#define HGRUNT_9MMAR ( 1 << 0) -#define HGRUNT_HANDGRENADE ( 1 << 1) -#define HGRUNT_GRENADELAUNCHER ( 1 << 2) -#define HGRUNT_SHOTGUN ( 1 << 3) - -#define HEAD_GROUP 1 -#define HEAD_GRUNT 0 -#define HEAD_COMMANDER 1 -#define HEAD_SHOTGUN 2 -#define HEAD_M203 3 -#define GUN_GROUP 2 -#define GUN_MP5 0 -#define GUN_SHOTGUN 1 -#define GUN_NONE 2 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HGRUNT_AE_RELOAD ( 2 ) -#define HGRUNT_AE_KICK ( 3 ) -#define HGRUNT_AE_BURST1 ( 4 ) -#define HGRUNT_AE_BURST2 ( 5 ) -#define HGRUNT_AE_BURST3 ( 6 ) -#define HGRUNT_AE_GREN_TOSS ( 7 ) -#define HGRUNT_AE_GREN_LAUNCH ( 8 ) -#define HGRUNT_AE_GREN_DROP ( 9 ) -#define HGRUNT_AE_CAUGHT_ENEMY ( 10) // grunt established sight with an enemy (player only) that had previously eluded the squad. -#define HGRUNT_AE_DROP_GUN ( 11) // grunt (probably dead) is dropping his mp5. - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_GRUNT_SUPPRESS = LAST_COMMON_SCHEDULE + 1, - SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE,// move to a location to set up an attack against the enemy. (usually when a friendly is in the way). - SCHED_GRUNT_COVER_AND_RELOAD, - SCHED_GRUNT_SWEEP, - SCHED_GRUNT_FOUND_ENEMY, - SCHED_GRUNT_REPEL, - SCHED_GRUNT_REPEL_ATTACK, - SCHED_GRUNT_REPEL_LAND, - SCHED_GRUNT_WAIT_FACE_ENEMY, - SCHED_GRUNT_TAKECOVER_FAILED,// special schedule type that forces analysis of conditions and picks the best possible schedule to recover from this type of failure. - SCHED_GRUNT_ELOF_FAIL, -}; - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_GRUNT_FACE_TOSS_DIR = LAST_COMMON_TASK + 1, - TASK_GRUNT_SPEAK_SENTENCE, - TASK_GRUNT_CHECK_FIRE, -}; - -//========================================================= -// monster-specific conditions -//========================================================= -#define bits_COND_GRUNT_NOFIRE ( bits_COND_SPECIAL1 ) - -class CHGrunt : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL FCanCheckAttacks ( void ); - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - void CheckAmmo ( void ); - void SetActivity ( Activity NewActivity ); - void StartTask ( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - void DeathSound( void ); - void PainSound( void ); - void IdleSound ( void ); - Vector GetGunPosition( void ); - void Shoot ( void ); - void Shotgun ( void ); - void PrescheduleThink ( void ); - void GibMonster( void ); - void SpeakSentence( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CBaseEntity *Kick( void ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - int IRelationship ( CBaseEntity *pTarget ); - - BOOL FOkToSpeak( void ); - void JustSpoke( void ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - // checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds, - // not every server frame. - float m_flNextGrenadeCheck; - float m_flNextPainTime; - float m_flLastEnemySightTime; - - Vector m_vecTossVelocity; - - BOOL m_fThrowGrenade; - BOOL m_fStanding; - BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter. - int m_cClipSize; - - int m_voicePitch; - - int m_iBrassShell; - int m_iShotgunShell; - - int m_iSentence; - - static const char *pGruntSentences[]; -}; - -LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt ); - -TYPEDESCRIPTION CHGrunt::m_SaveData[] = -{ - DEFINE_FIELD( CHGrunt, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CHGrunt, m_flNextPainTime, FIELD_TIME ), -// DEFINE_FIELD( CHGrunt, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero - DEFINE_FIELD( CHGrunt, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CHGrunt, m_fThrowGrenade, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fStanding, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_fFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( CHGrunt, m_cClipSize, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_voicePitch, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), - DEFINE_FIELD( CHGrunt, m_iSentence, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CHGrunt, CSquadMonster ); - -const char *CHGrunt::pGruntSentences[] = -{ - "HG_GREN", // grenade scared grunt - "HG_ALERT", // sees player - "HG_MONSTER", // sees monster - "HG_COVER", // running to cover - "HG_THROW", // about to throw grenade - "HG_CHARGE", // running out to get the enemy - "HG_TAUNT", // say rude things -}; - -enum -{ - HGRUNT_SENT_NONE = -1, - HGRUNT_SENT_GREN = 0, - HGRUNT_SENT_ALERT, - HGRUNT_SENT_MONSTER, - HGRUNT_SENT_COVER, - HGRUNT_SENT_THROW, - HGRUNT_SENT_CHARGE, - HGRUNT_SENT_TAUNT, -}; - -//========================================================= -// Speak Sentence - say your cued up sentence. -// -// Some grunt sentences (take cover and charge) rely on actually -// being able to execute the intended action. It's really lame -// when a grunt says 'COVER ME' and then doesn't move. The problem -// is that the sentences were played when the decision to TRY -// to move to cover was made. Now the sentence is played after -// we know for sure that there is a valid path. The schedule -// may still fail but in most cases, well after the grunt has -// started moving. -//========================================================= -void CHGrunt :: SpeakSentence( void ) -{ - if ( m_iSentence == HGRUNT_SENT_NONE ) - { - // no sentence cued up. - return; - } - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), pGruntSentences[ m_iSentence ], HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } -} - -//========================================================= -// IRelationship - overridden because Alien Grunts are -// Human Grunt's nemesis. -//========================================================= -int CHGrunt::IRelationship ( CBaseEntity *pTarget ) -{ - if ( FClassnameIs( pTarget->pev, "monster_alien_grunt" ) || ( FClassnameIs( pTarget->pev, "monster_gargantua" ) ) ) - { - return R_NM; - } - - return CSquadMonster::IRelationship( pTarget ); -} - -//========================================================= -// GibMonster - make gun fly through the air. -//========================================================= -void CHGrunt :: GibMonster ( void ) -{ - Vector vecGunPos; - Vector vecGunAngles; - - if ( GetBodygroup( 2 ) != 2 ) - {// throw a gun if the grunt has one - GetAttachment( 0, vecGunPos, vecGunAngles ); - - CBaseEntity *pGun; - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - if ( pGun ) - { - pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - pGun->pev->avelocity = Vector ( 0, RANDOM_FLOAT( 200, 400 ), 0 ); - } - - if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - pGun = DropItem( "ammo_ARgrenades", vecGunPos, vecGunAngles ); - if ( pGun ) - { - pGun->pev->velocity = Vector (RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - pGun->pev->avelocity = Vector ( 0, RANDOM_FLOAT( 200, 400 ), 0 ); - } - } - } - - CBaseMonster :: GibMonster(); -} - -//========================================================= -// ISoundMask - Overidden for human grunts because they -// hear the DANGER sound that is made by hand grenades and -// other dangerous items. -//========================================================= -int CHGrunt :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// someone else is talking - don't speak -//========================================================= -BOOL CHGrunt :: FOkToSpeak( void ) -{ -// if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // no talking outside of combat if gagged. - return FALSE; - } - } - - // if player is not in pvs, don't speak -// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -void CHGrunt :: JustSpoke( void ) -{ - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); - m_iSentence = HGRUNT_SENT_NONE; -} - -//========================================================= -// PrescheduleThink - this function runs after conditions -// are collected and before scheduling code is run. -//========================================================= -void CHGrunt :: PrescheduleThink ( void ) -{ - if ( InSquad() && m_hEnemy != 0 ) - { - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // update the squad's last enemy sighting time. - MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; - } - else - { - if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) - { - // been a while since we've seen the enemy - MySquadLeader()->m_fEnemyEluded = TRUE; - } - } - } -} - -//========================================================= -// FCanCheckAttacks - this is overridden for human grunts -// because they can throw/shoot grenades when they can't see their -// target and the base class doesn't check attacks if the monster -// cannot see its enemy. -// -// !!!BUGBUG - this gets called before a 3-round burst is fired -// which means that a friendly can still be hit with up to 2 rounds. -// ALSO, grenades will not be tossed if there is a friendly in front, -// this is a bad bug. Friendly machine gun fire avoidance -// will unecessarily prevent the throwing of a grenade as well. -//========================================================= -BOOL CHGrunt :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CHGrunt :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - CBaseMonster *pEnemy = NULL; - - if ( m_hEnemy != 0 ) - { - pEnemy = m_hEnemy->MyMonsterPointer(); - - if ( !pEnemy ) - { - return FALSE; - } - } - - if ( flDist <= 64 && flDot >= 0.7 && - pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON && - pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack1 - overridden for HGrunt, cause -// FCanCheckAttacks() doesn't disqualify all attacks based -// on whether or not the enemy is occluded because unlike -// the base class, the HGrunt can attack when the enemy is -// occluded (throw grenade over wall, etc). We must -// disqualify the machine gun attack if the enemy is occluded. -//========================================================= -BOOL CHGrunt :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - - if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) - { - // kick nonclients, but don't shoot at them. - return FALSE; - } - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 ) - { - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - this checks the Grunt's grenade -// attack. -//========================================================= -BOOL CHGrunt :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if (! FBitSet(pev->weapons, (HGRUNT_HANDGRENADE | HGRUNT_GRENADELAUNCHER))) - { - return FALSE; - } - - // if the grunt isn't moving, it's ok to check. - if ( m_flGroundSpeed != 0 ) - { - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - // assume things haven't changed too much since last time - if (gpGlobals->time < m_flNextGrenadeCheck ) - { - return m_fThrowGrenade; - } - - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - Vector vecTarget; - - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) - { - // find feet - if (RANDOM_LONG(0,1)) - { - // magically know where they are - vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); - } - else - { - // toss it to where you last saw them - vecTarget = m_vecEnemyLKP; - } - // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; - } - else - { - // find target - // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - if (HasConditions( bits_COND_SEE_ENEMY)) - vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity; - } - - // are any of my squad members near the intended grenade impact area? - if ( InSquad() ) - { - if (SquadMemberInRange( vecTarget, 256 )) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - } - } - - if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) - { - // crap, I don't want to blow myself up - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - - if (FBitSet( pev->weapons, HGRUNT_HANDGRENADE)) - { - Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - else - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - - - - return m_fThrowGrenade; -} - - -//========================================================= -// TraceAttack - make sure we're not taking it in the helmet -//========================================================= -void CHGrunt :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // check for helmet shot - if (ptr->iHitgroup == 11) - { - // make sure we're wearing one - if (GetBodygroup( 1 ) == HEAD_GRUNT && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) - { - // absorb damage - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // it's head shot anyways - ptr->iHitgroup = HITGROUP_HEAD; - } - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -//========================================================= -// TakeDamage - overridden for the grunt because the grunt -// needs to forget that he is in cover if he's hurt. (Obviously -// not in a safe place anymore). -//========================================================= -int CHGrunt :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - Forget( bits_MEMORY_INCOVER ); - - return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHGrunt :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 150; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RANGE_ATTACK1: - ys = 120; - break; - case ACT_RANGE_ATTACK2: - ys = 120; - break; - case ACT_MELEE_ATTACK1: - ys = 120; - break; - case ACT_MELEE_ATTACK2: - ys = 120; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_GLIDE: - case ACT_FLY: - ys = 30; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -void CHGrunt :: IdleSound( void ) -{ - if (FOkToSpeak() && (g_fGruntQuestion || RANDOM_LONG(0,1))) - { - if (!g_fGruntQuestion) - { - // ask question or make statement - switch (RANDOM_LONG(0,2)) - { - case 0: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fGruntQuestion = 1; - break; - case 1: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fGruntQuestion = 2; - break; - case 2: // statement - SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - } - else - { - switch (g_fGruntQuestion) - { - case 1: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - case 2: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - g_fGruntQuestion = 0; - } - JustSpoke(); - } -} - -//========================================================= -// CheckAmmo - overridden for the grunt because he actually -// uses ammo! (base class doesn't) -//========================================================= -void CHGrunt :: CheckAmmo ( void ) -{ - if ( m_cAmmoLoaded <= 0 ) - { - SetConditions(bits_COND_NO_AMMO_LOADED); - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHGrunt :: Classify ( void ) -{ - return CLASS_HUMAN_MILITARY; -} - -//========================================================= -//========================================================= -CBaseEntity *CHGrunt :: Kick( void ) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - return pEntity; - } - - return NULL; -} - -//========================================================= -// GetGunPosition return the end of the barrel -//========================================================= - -Vector CHGrunt :: GetGunPosition( ) -{ - if (m_fStanding ) - { - return pev->origin + Vector( 0, 0, 60 ); - } - else - { - return pev->origin + Vector( 0, 0, 48 ); - } -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt :: Shoot ( void ) -{ - if (m_hEnemy == 0) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// Shoot -//========================================================= -void CHGrunt :: Shotgun ( void ) -{ - if (m_hEnemy == 0) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL); - FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHGrunt :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - Vector vecShootDir; - Vector vecShootOrigin; - - switch( pEvent->event ) - { - case HGRUNT_AE_DROP_GUN: - { - Vector vecGunPos; - Vector vecGunAngles; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - // switch to body group with no gun. - SetBodygroup( GUN_GROUP, GUN_NONE ); - - // now spawn a gun. - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - DropItem( "weapon_shotgun", vecGunPos, vecGunAngles ); - } - else - { - DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles ); - } - if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles ); - } - - } - break; - - case HGRUNT_AE_RELOAD: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_reload1.wav", 1, ATTN_NORM ); - m_cAmmoLoaded = m_cClipSize; - ClearConditions(bits_COND_NO_AMMO_LOADED); - break; - - case HGRUNT_AE_GREN_TOSS: - { - UTIL_MakeVectors( pev->angles ); - // CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 34 + Vector (0, 0, 32), m_vecTossVelocity, 3.5 ); - CGrenade::ShootTimed( pev, GetGunPosition(), m_vecTossVelocity, 3.5 ); - - m_fThrowGrenade = FALSE; - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - // !!!LATER - when in a group, only try to throw grenade if ordered. - } - break; - - case HGRUNT_AE_GREN_LAUNCH: - { - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM); - CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); - m_fThrowGrenade = FALSE; - if (g_iSkillLevel == SKILL_HARD) - m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again - else - m_flNextGrenadeCheck = gpGlobals->time + 6;// wait six seconds before even looking again to see if a grenade can be thrown. - } - break; - - case HGRUNT_AE_GREN_DROP: - { - UTIL_MakeVectors( pev->angles ); - CGrenade::ShootTimed( pev, pev->origin + gpGlobals->v_forward * 17 - gpGlobals->v_right * 27 + gpGlobals->v_up * 6, g_vecZero, 3 ); - } - break; - - case HGRUNT_AE_BURST1: - { - if ( FBitSet( pev->weapons, HGRUNT_9MMAR )) - { - Shoot(); - - // the first round of the three round burst plays the sound and puts a sound in the world sound list. - if ( RANDOM_LONG(0,1) ) - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM ); - } - } - else - { - Shotgun( ); - - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); - } - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); - } - break; - - case HGRUNT_AE_BURST2: - case HGRUNT_AE_BURST3: - Shoot(); - break; - - case HGRUNT_AE_KICK: - { - CBaseEntity *pHurt = Kick(); - - if ( pHurt ) - { - // SOUND HERE! - UTIL_MakeVectors( pev->angles ); - pHurt->pev->punchangle.x = 15; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50; - pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB ); - } - } - break; - - case HGRUNT_AE_CAUGHT_ENEMY: - { - if ( FOkToSpeak() ) - { - SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - - } - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHGrunt :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->effects = 0; - pev->health = gSkillData.hgruntHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_flNextGrenadeCheck = gpGlobals->time + 1; - m_flNextPainTime = gpGlobals->time; - m_iSentence = HGRUNT_SENT_NONE; - - m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; - - m_fEnemyEluded = FALSE; - m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. - - m_HackedGunPos = Vector ( 0, 0, 55 ); - - if (pev->weapons == 0) - { - // initialize to original values - pev->weapons = HGRUNT_9MMAR | HGRUNT_HANDGRENADE; - // pev->weapons = HGRUNT_SHOTGUN; - // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; - } - - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - m_cClipSize = 8; - } - else - { - m_cClipSize = GRUNT_CLIP_SIZE; - } - m_cAmmoLoaded = m_cClipSize; - - if (RANDOM_LONG( 0, 99 ) < 80) - pev->skin = 0; // light skin - else - pev->skin = 1; // dark skin - - if (FBitSet( pev->weapons, HGRUNT_SHOTGUN )) - { - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); - } - else if (FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER )) - { - SetBodygroup( HEAD_GROUP, HEAD_M203 ); - pev->skin = 1; // alway dark skin - } - - CTalkMonster::g_talkWaitTime = 0; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHGrunt :: Precache() -{ - PRECACHE_MODEL("models/hgrunt.mdl"); - - PRECACHE_SOUND( "hgrunt/gr_mgun1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_mgun2.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_die1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_die3.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_pain1.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain2.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain3.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain4.wav" ); - PRECACHE_SOUND( "hgrunt/gr_pain5.wav" ); - - PRECACHE_SOUND( "hgrunt/gr_reload1.wav" ); - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - - PRECACHE_SOUND( "weapons/sbarrel1.wav" ); - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event - - // get voice pitch - if (RANDOM_LONG(0,1)) - m_voicePitch = 109 + RANDOM_LONG(0,7); - else - m_voicePitch = 100; - - m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl"); -} - -//========================================================= -// start task -//========================================================= -void CHGrunt :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_GRUNT_CHECK_FIRE: - if ( !NoFriendlyFire() ) - { - SetConditions( bits_COND_GRUNT_NOFIRE ); - } - TaskComplete(); - break; - - case TASK_GRUNT_SPEAK_SENTENCE: - SpeakSentence(); - TaskComplete(); - break; - - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // grunt no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - CSquadMonster ::StartTask( pTask ); - break; - - case TASK_RELOAD: - m_IdealActivity = ACT_RELOAD; - break; - - case TASK_GRUNT_FACE_TOSS_DIR: - break; - - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - CSquadMonster :: StartTask( pTask ); - if (pev->movetype == MOVETYPE_FLY) - { - m_IdealActivity = ACT_GLIDE; - } - break; - - default: - CSquadMonster :: StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CHGrunt :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_GRUNT_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CSquadMonster :: RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CHGrunt :: PainSound ( void ) -{ - if ( gpGlobals->time > m_flNextPainTime ) - { -#if 0 - if ( RANDOM_LONG(0,99) < 5 ) - { - // pain sentences are rare - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", HGRUNT_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); - JustSpoke(); - return; - } - } -#endif - switch ( RANDOM_LONG(0,6) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); - break; - } - - m_flNextPainTime = gpGlobals->time + 1; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHGrunt :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); - break; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// GruntFail -//========================================================= -Task_t tlGruntFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntFail[] = -{ - { - tlGruntFail, - ARRAYSIZE ( tlGruntFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - 0, - "Grunt Fail" - }, -}; - -//========================================================= -// Grunt Combat Fail -//========================================================= -Task_t tlGruntCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slGruntCombatFail[] = -{ - { - tlGruntCombatFail, - ARRAYSIZE ( tlGruntCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Grunt Combat Fail" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlGruntVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, -}; - -Schedule_t slGruntVictoryDance[] = -{ - { - tlGruntVictoryDance, - ARRAYSIZE ( tlGruntVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "GruntVictoryDance" - }, -}; - -//========================================================= -// Establish line of fire - move to a position that allows -// the grunt to attack. -//========================================================= -Task_t tlGruntEstablishLineOfFire[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_ELOF_FAIL }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slGruntEstablishLineOfFire[] = -{ - { - tlGruntEstablishLineOfFire, - ARRAYSIZE ( tlGruntEstablishLineOfFire ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntEstablishLineOfFire" - }, -}; - -//========================================================= -// GruntFoundEnemy - grunt established sight with an enemy -// that was hiding from the squad. -//========================================================= -Task_t tlGruntFoundEnemy[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, -}; - -Schedule_t slGruntFoundEnemy[] = -{ - { - tlGruntFoundEnemy, - ARRAYSIZE ( tlGruntFoundEnemy ), - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntFoundEnemy" - }, -}; - -//========================================================= -// GruntCombatFace Schedule -//========================================================= -Task_t tlGruntCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_SWEEP }, -}; - -Schedule_t slGruntCombatFace[] = -{ - { - tlGruntCombatFace1, - ARRAYSIZE ( tlGruntCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Suppressing fire - don't stop shooting until the clip is -// empty or grunt gets hurt. -//========================================================= -Task_t tlGruntSignalSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSignalSuppress[] = -{ - { - tlGruntSignalSuppress, - ARRAYSIZE ( tlGruntSignalSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "SignalSuppress" - }, -}; - -Task_t tlGruntSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntSuppress[] = -{ - { - tlGruntSuppress, - ARRAYSIZE ( tlGruntSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Suppress" - }, -}; - - -//========================================================= -// grunt wait in cover - we don't allow danger or the ability -// to attack to break a grunt's run to cover schedule, but -// when a grunt is in cover, we do want them to attack if they can. -//========================================================= -Task_t tlGruntWaitInCover[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slGruntWaitInCover[] = -{ - { - tlGruntWaitInCover, - ARRAYSIZE ( tlGruntWaitInCover ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - - bits_SOUND_DANGER, - "GruntWaitInCover" - }, -}; - -//========================================================= -// run to cover. -// !!!BUGBUG - set a decent fail schedule here. -//========================================================= -Task_t tlGruntTakeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_GRUNT_TAKECOVER_FAILED }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_GRUNT_SPEAK_SENTENCE, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntTakeCover[] = -{ - { - tlGruntTakeCover1, - ARRAYSIZE ( tlGruntTakeCover1 ), - 0, - 0, - "TakeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntGrenadeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, - { TASK_CLEAR_MOVE_WAIT, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY }, -}; - -Schedule_t slGruntGrenadeCover[] = -{ - { - tlGruntGrenadeCover1, - ARRAYSIZE ( tlGruntGrenadeCover1 ), - 0, - 0, - "GrenadeCover" - }, -}; - - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlGruntTossGrenadeCover1[] = -{ - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slGruntTossGrenadeCover[] = -{ - { - tlGruntTossGrenadeCover1, - ARRAYSIZE ( tlGruntTossGrenadeCover1 ), - 0, - 0, - "TossGrenadeCover" - }, -}; - -//========================================================= -// hide from the loudest sound source (to run from grenade) -//========================================================= -Task_t tlGruntTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slGruntTakeCoverFromBestSound[] = -{ - { - tlGruntTakeCoverFromBestSound, - ARRAYSIZE ( tlGruntTakeCoverFromBestSound ), - 0, - 0, - "GruntTakeCoverFromBestSound" - }, -}; - -//========================================================= -// Grunt reload schedule -//========================================================= -Task_t tlGruntHideReload[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, -}; - -Schedule_t slGruntHideReload[] = -{ - { - tlGruntHideReload, - ARRAYSIZE ( tlGruntHideReload ), - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "GruntHideReload" - } -}; - -//========================================================= -// Do a turning sweep of the area -//========================================================= -Task_t tlGruntSweep[] = -{ - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slGruntSweep[] = -{ - { - tlGruntSweep, - ARRAYSIZE ( tlGruntSweep ), - - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_WORLD |// sound flags - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - - "Grunt Sweep" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1A[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1A[] = -{ - { - tlGruntRangeAttack1A, - ARRAYSIZE ( tlGruntRangeAttack1A ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND | - bits_COND_GRUNT_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Range Attack1A" - }, -}; - - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack1B[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_GRUNT_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slGruntRangeAttack1B[] = -{ - { - tlGruntRangeAttack1B, - ARRAYSIZE ( tlGruntRangeAttack1B ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_GRUNT_NOFIRE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1B" - }, -}; - -//========================================================= -// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlGruntRangeAttack2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GRUNT_FACE_TOSS_DIR, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, - { TASK_SET_SCHEDULE, (float)SCHED_GRUNT_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. -}; - -Schedule_t slGruntRangeAttack2[] = -{ - { - tlGruntRangeAttack2, - ARRAYSIZE ( tlGruntRangeAttack2 ), - 0, - 0, - "RangeAttack2" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepel[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, -}; - -Schedule_t slGruntRepel[] = -{ - { - tlGruntRepel, - ARRAYSIZE ( tlGruntRepel ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlGruntRepelAttack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, -}; - -Schedule_t slGruntRepelAttack[] = -{ - { - tlGruntRepelAttack, - ARRAYSIZE ( tlGruntRepelAttack ), - bits_COND_ENEMY_OCCLUDED, - 0, - "Repel Attack" - }, -}; - -//========================================================= -// repel land -//========================================================= -Task_t tlGruntRepelLand[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slGruntRepelLand[] = -{ - { - tlGruntRepelLand, - ARRAYSIZE ( tlGruntRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel Land" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CHGrunt ) -{ - slGruntFail, - slGruntCombatFail, - slGruntVictoryDance, - slGruntEstablishLineOfFire, - slGruntFoundEnemy, - slGruntCombatFace, - slGruntSignalSuppress, - slGruntSuppress, - slGruntWaitInCover, - slGruntTakeCover, - slGruntGrenadeCover, - slGruntTossGrenadeCover, - slGruntTakeCoverFromBestSound, - slGruntHideReload, - slGruntSweep, - slGruntRangeAttack1A, - slGruntRangeAttack1B, - slGruntRangeAttack2, - slGruntRepel, - slGruntRepelAttack, - slGruntRepelLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHGrunt, CSquadMonster ); - -//========================================================= -// SetActivity -//========================================================= -void CHGrunt :: SetActivity ( Activity NewActivity ) -{ - int iSequence = ACTIVITY_NOT_AVAILABLE; - - switch ( NewActivity) - { - case ACT_RANGE_ATTACK1: - // grunt is either shooting standing or shooting crouched - if (FBitSet( pev->weapons, HGRUNT_9MMAR)) - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_mp5" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_mp5" ); - } - } - else - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_shotgun" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_shotgun" ); - } - } - break; - case ACT_RANGE_ATTACK2: - // grunt is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if ( pev->weapons & HGRUNT_HANDGRENADE ) - { - // get toss anim - iSequence = LookupSequence( "throwgrenade" ); - } - else - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - break; - case ACT_RUN: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_RUN_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_WALK: - if ( pev->health <= HGRUNT_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_WALK_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_IDLE: - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - NewActivity = ACT_IDLE_ANGRY; - } - iSequence = LookupActivity ( NewActivity ); - break; - default: - iSequence = LookupActivity ( NewActivity ); - break; - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// Get Schedule! -//========================================================= -Schedule_t *CHGrunt :: GetSchedule( void ) -{ - - // clear old sentence - m_iSentence = HGRUNT_SENT_NONE; - - // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling. - if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) - { - if (pev->flags & FL_ONGROUND) - { - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_GRUNT_REPEL_LAND ); - } - else - { - // repel down a rope, - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_GRUNT_REPEL_ATTACK ); - else - return GetScheduleOfType ( SCHED_GRUNT_REPEL ); - } - } - - // grunts place HIGH priority on running away from danger sounds. - if ( HasConditions(bits_COND_HEAR_SOUND) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound) - { - if (pSound->m_iType & bits_SOUND_DANGER) - { - // dangerous sound nearby! - - //!!!KELLY - currently, this is the grunt's signal that a grenade has landed nearby, - // and the grunt should find cover from the blast - // good place for "SHIT!" or some other colorful verbal indicator of dismay. - // It's not safe to play a verbal order here "Scatter", etc cause - // this may only affect a single individual in a squad. - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_GREN", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - /* - if (!HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & (bits_SOUND_PLAYER | bits_SOUND_COMBAT) )) - { - MakeIdealYaw( pSound->m_vecOrigin ); - } - */ - } - } - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - -// new enemy - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - if ( InSquad() ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - - if ( !IsLeader() ) - { - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - //!!!KELLY - the leader of a squad of grunts has just seen the player or a - // monster and has made it the squad's enemy. You - // can check pev->flags for FL_CLIENT to determine whether this is the player - // or a monster. He's going to immediately start - // firing, though. If you'd like, we can make an alternate "first sight" - // schedule where the leader plays a handsign anim - // that gives us enough time to hear a short sentence or spoken command - // before he starts pluggin away. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - if ((m_hEnemy != 0) && m_hEnemy->IsPlayer()) - // player - SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - else if ((m_hEnemy != 0) && - (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) && - (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) && - (m_hEnemy->Classify() != CLASS_MACHINE)) - // monster - SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - - JustSpoke(); - } - - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_GRUNT_SUPPRESS ); - } - else - { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - } - } -// no ammo - else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) - { - //!!!KELLY - this individual just realized he's out of bullet ammo. - // He's going to try to find cover to run to and reload, but rarely, if - // none is available, he'll drop and reload in the open here. - return GetScheduleOfType ( SCHED_GRUNT_COVER_AND_RELOAD ); - } - -// damaged just a little - else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - // if hurt: - // 90% chance of taking cover - // 10% chance of flinch. - int iPercent = RANDOM_LONG(0,99); - - if ( iPercent <= 90 && m_hEnemy != 0 ) - { - // only try to take cover if we actually have an enemy! - - //!!!KELLY - this grunt was hit and is going to run to cover. - if (FOkToSpeak()) // && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - m_iSentence = HGRUNT_SENT_COVER; - //JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - } -// can kick - else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } -// can grenade launch - - else if ( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER) && HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // shoot a grenade if you can - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } -// can shoot - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if ( InSquad() ) - { - // if the enemy has eluded the squad and a squad member has just located the enemy - // and the enemy does not see the squad member, issue a call to the squad to waste a - // little time and give the player a chance to turn. - if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - return GetScheduleOfType ( SCHED_GRUNT_FOUND_ENEMY ); - } - } - - if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - // try to take an available ENGAGE slot - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // throw a grenade if can and no engage slots are available - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else - { - // hide! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } -// can't see enemy - else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - //!!!KELLY - this grunt is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else if ( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - //!!!KELLY - grunt cannot see the enemy and has just decided to - // charge the enemy's position. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - m_iSentence = HGRUNT_SENT_CHARGE; - //JustSpoke(); - } - - return GetScheduleOfType( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - else - { - //!!!KELLY - grunt is going to stay put for a couple seconds to see if - // the enemy wanders back out into the open, or approaches the - // grunt's covered position. Good place for a taunt, I guess? - if (FOkToSpeak() && RANDOM_LONG(0,1)) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_STANDOFF ); - } - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE ); - } - } - default: - break; - } - - // no special cases here, call the base class - return CSquadMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CHGrunt :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - { - if ( InSquad() ) - { - if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return slGruntTossGrenadeCover; - } - else - { - return &slGruntTakeCover[ 0 ]; - } - } - else - { - if ( RANDOM_LONG(0,1) ) - { - return &slGruntTakeCover[ 0 ]; - } - else - { - return &slGruntGrenadeCover[ 0 ]; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slGruntTakeCoverFromBestSound[ 0 ]; - } - case SCHED_GRUNT_TAKECOVER_FAILED: - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_FAIL ); - } - break; - case SCHED_GRUNT_ELOF_FAIL: - { - // human grunt is unable to move to a position that allows him to attack the enemy. - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case SCHED_GRUNT_ESTABLISH_LINE_OF_FIRE: - { - return &slGruntEstablishLineOfFire[ 0 ]; - } - break; - case SCHED_RANGE_ATTACK1: - { - // randomly stand or crouch - if (RANDOM_LONG(0,9) == 0) - m_fStanding = RANDOM_LONG(0,1); - - if (m_fStanding) - return &slGruntRangeAttack1B[ 0 ]; - else - return &slGruntRangeAttack1A[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slGruntRangeAttack2[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slGruntCombatFace[ 0 ]; - } - case SCHED_GRUNT_WAIT_FACE_ENEMY: - { - return &slGruntWaitInCover[ 0 ]; - } - case SCHED_GRUNT_SWEEP: - { - return &slGruntSweep[ 0 ]; - } - case SCHED_GRUNT_COVER_AND_RELOAD: - { - return &slGruntHideReload[ 0 ]; - } - case SCHED_GRUNT_FOUND_ENEMY: - { - return &slGruntFoundEnemy[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - if ( InSquad() ) - { - if ( !IsLeader() ) - { - return &slGruntFail[ 0 ]; - } - } - - return &slGruntVictoryDance[ 0 ]; - } - case SCHED_GRUNT_SUPPRESS: - { - if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) - { - m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slGruntSignalSuppress[ 0 ]; - } - else - { - return &slGruntSuppress[ 0 ]; - } - } - case SCHED_FAIL: - { - if ( m_hEnemy != 0 ) - { - // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slGruntCombatFail[ 0 ]; - } - - return &slGruntFail[ 0 ]; - } - case SCHED_GRUNT_REPEL: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepel[ 0 ]; - } - case SCHED_GRUNT_REPEL_ATTACK: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slGruntRepelAttack[ 0 ]; - } - case SCHED_GRUNT_REPEL_LAND: - { - return &slGruntRepelLand[ 0 ]; - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - - -//========================================================= -// CHGruntRepel - when triggered, spawns a monster_human_grunt -// repelling down a line. -//========================================================= - -class CHGruntRepel : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void EXPORT RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int m_iSpriteTexture; // Don't save, precache -}; - -LINK_ENTITY_TO_CLASS( monster_grunt_repel, CHGruntRepel ); - -void CHGruntRepel::Spawn( void ) -{ - Precache( ); - pev->solid = SOLID_NOT; - - SetUse( &CHGruntRepel::RepelUse ); -} - -void CHGruntRepel::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); -} - -void CHGruntRepel::RepelUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr); - /* - if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) - return NULL; - */ - - CBaseEntity *pEntity = Create( "monster_human_grunt", pev->origin, pev->angles ); - CBaseMonster *pGrunt = pEntity->MyMonsterPointer( ); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); - pGrunt->SetActivity( ACT_GLIDE ); - // UNDONE: position? - pGrunt->m_vecLastPosition = tr.vecEndPos; - - CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( pev->origin + Vector(0,0,112), pGrunt->entindex() ); - pBeam->SetFlags( BEAM_FSOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &CBeam::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; - - UTIL_Remove( this ); -} - - - -//========================================================= -// DEAD HGRUNT PROP -//========================================================= -class CDeadHGrunt : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static const char *m_szPoses[3]; -}; - -const char *CDeadHGrunt::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; - -void CDeadHGrunt::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CDeadHGrunt ); - -//========================================================= -// ********** DeadHGrunt SPAWN ********** -//========================================================= -void CDeadHGrunt :: Spawn( void ) -{ - PRECACHE_MODEL("models/hgrunt.mdl"); - SET_MODEL(ENT(pev), "models/hgrunt.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead hgrunt with bad pose\n" ); - } - - // Corpses have less health - pev->health = 8; - - // map old bodies onto new bodies - switch( pev->body ) - { - case 0: // Grunt with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 1: // Commander with Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_MP5 ); - break; - case 2: // Grunt no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_GRUNT ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - case 3: // Commander no Gun - pev->body = 0; - pev->skin = 0; - SetBodygroup( HEAD_GROUP, HEAD_COMMANDER ); - SetBodygroup( GUN_GROUP, GUN_NONE ); - break; - } - - MonsterInitDead(); -} diff --git a/sdk/dlls/hl.def b/sdk/dlls/hl.def deleted file mode 100644 index b4211ab..0000000 --- a/sdk/dlls/hl.def +++ /dev/null @@ -1,5 +0,0 @@ -LIBRARY hl -EXPORTS - GiveFnptrsToDll @1 -SECTIONS - .data READ WRITE diff --git a/sdk/dlls/hl.dsp b/sdk/dlls/hl.dsp deleted file mode 100644 index 13ef157..0000000 --- a/sdk/dlls/hl.dsp +++ /dev/null @@ -1,1637 +0,0 @@ -# Microsoft Developer Studio Project File - Name="hl" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=hl - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "hl.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "hl.mak" CFG="hl - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "hl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "hl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "hl - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\Release" -# PROP BASE Intermediate_Dir ".\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir ".\Releasehl" -# PROP Intermediate_Dir ".\Releasehl" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G5 /MT /W3 /GR /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /I "..\public" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /Fr /YX /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /def:".\hl.def" -# SUBTRACT LINK32 /profile -# Begin Custom Build -InputDir=.\Releasehl -ProjDir=. -InputPath=.\Releasehl\hl.dll -InputName=hl -SOURCE="$(InputPath)" - -BuildCmds= \ - call ..\filecopy.bat $(InputPath) $(ProjDir)\..\..\game\mod\dlls\$(InputName).dll \ - call ..\filecopy.bat $(InputDir)\$(InputName).pdb $(ProjDir)\..\..\game\moddlls\$(InputName).pdb \ - - -"$(ProjDir)\..\..\game\mod\dlls\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) - -"$(ProjDir)\..\..\game\mod\dlls\$(InputName).pdb" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - $(BuildCmds) -# End Custom Build - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir ".\hl___Win" -# PROP BASE Intermediate_Dir ".\hl___Win" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir ".\debughl" -# PROP Intermediate_Dir ".\debughl" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G5 /MTd /W3 /Gm /ZI /Od /I "..\\" /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /I "..\public" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /FR /YX /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /i "..\engine" /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 -# ADD LINK32 user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" /implib:".\Debug\hl.lib" -# SUBTRACT LINK32 /profile -# Begin Custom Build -ProjDir=. -InputPath=.\debughl\hl.dll -InputName=hl -SOURCE="$(InputPath)" - -"$(ProjDir)\..\..\game\mod\dlls\$(InputName).dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - call ..\filecopy.bat $(InputPath) $(ProjDir)\..\..\game\mod\dlls\$(InputName).dll - -# End Custom Build - -!ENDIF - -# Begin Target - -# Name "hl - Win32 Release" -# Name "hl - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\aflock.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\agrunt.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\airtank.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\animating.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\animation.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\apache.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\barnacle.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\barney.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\bigmomma.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\bloater.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\bmodels.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\bullsquid.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\buttons.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\cbase.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\client.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\combat.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\controller.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\crossbow.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\crowbar.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\defaultai.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\doors.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\effects.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\egon.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\explode.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\flyingmonster.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\func_break.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\func_tank.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\game.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\gamerules.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\gargantua.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\gauss.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\genericmonster.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\ggrenade.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\globals.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\gman.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\h_ai.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\h_battery.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\h_cine.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\h_cycler.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\h_export.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\handgrenade.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\hassassin.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\headcrab.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\healthkit.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\hgrunt.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\wpn_shared\hl_wpn_glock.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\hornet.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\hornetgun.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\houndeye.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\ichthyosaur.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\islave.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\items.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\leech.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\lights.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\maprules.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\monstermaker.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\monsters.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\monsterstate.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\mortar.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\mp5.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\multiplay_gamerules.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\nihilanth.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\nodes.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\observer.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\osprey.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\pathcorner.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\plane.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\plats.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\player.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_debug.c - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_math.c - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_shared.c - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\python.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\rat.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\roach.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\rpg.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\satchel.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\schedule.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\scientist.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\scripted.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\shotgun.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\singleplay_gamerules.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\skill.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\sound.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\soundent.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\spectator.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\squadmonster.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\squeakgrenade.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\subs.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\talkmonster.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\teamplay_gamerules.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\tempmonster.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\tentacle.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\triggers.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\tripmine.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\turret.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\util.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\game_shared\voice_gamemgr.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\weapons.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\world.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\xen.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\zombie.cpp - -!IF "$(CFG)" == "hl - Win32 Release" - -!ELSEIF "$(CFG)" == "hl - Win32 Debug" - -# ADD CPP /GR - -!ENDIF - -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" -# Begin Source File - -SOURCE=.\activity.h -# End Source File -# Begin Source File - -SOURCE=.\activitymap.h -# End Source File -# Begin Source File - -SOURCE=.\animation.h -# End Source File -# Begin Source File - -SOURCE=.\basemonster.h -# End Source File -# Begin Source File - -SOURCE=.\cbase.h -# End Source File -# Begin Source File - -SOURCE=.\cdll_dll.h -# End Source File -# Begin Source File - -SOURCE=.\client.h -# End Source File -# Begin Source File - -SOURCE=.\decals.h -# End Source File -# Begin Source File - -SOURCE=.\defaultai.h -# End Source File -# Begin Source File - -SOURCE=.\doors.h -# End Source File -# Begin Source File - -SOURCE=.\effects.h -# End Source File -# Begin Source File - -SOURCE=..\engine\eiface.h -# End Source File -# Begin Source File - -SOURCE=.\enginecallback.h -# End Source File -# Begin Source File - -SOURCE=.\explode.h -# End Source File -# Begin Source File - -SOURCE=.\extdll.h -# End Source File -# Begin Source File - -SOURCE=.\flyingmonster.h -# End Source File -# Begin Source File - -SOURCE=.\func_break.h -# End Source File -# Begin Source File - -SOURCE=.\gamerules.h -# End Source File -# Begin Source File - -SOURCE=.\hornet.h -# End Source File -# Begin Source File - -SOURCE=.\items.h -# End Source File -# Begin Source File - -SOURCE=.\monsterevent.h -# End Source File -# Begin Source File - -SOURCE=.\monsters.h -# End Source File -# Begin Source File - -SOURCE=.\nodes.h -# End Source File -# Begin Source File - -SOURCE=.\plane.h -# End Source File -# Begin Source File - -SOURCE=.\player.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_debug.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_defs.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_info.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_materials.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_movevars.h -# End Source File -# Begin Source File - -SOURCE=..\pm_shared\pm_shared.h -# End Source File -# Begin Source File - -SOURCE=.\saverestore.h -# End Source File -# Begin Source File - -SOURCE=.\schedule.h -# End Source File -# Begin Source File - -SOURCE=.\scripted.h -# End Source File -# Begin Source File - -SOURCE=.\scriptevent.h -# End Source File -# Begin Source File - -SOURCE=.\skill.h -# End Source File -# Begin Source File - -SOURCE=.\soundent.h -# End Source File -# Begin Source File - -SOURCE=.\spectator.h -# End Source File -# Begin Source File - -SOURCE=.\squadmonster.h -# End Source File -# Begin Source File - -SOURCE=.\talkmonster.h -# End Source File -# Begin Source File - -SOURCE=.\teamplay_gamerules.h -# End Source File -# Begin Source File - -SOURCE=.\trains.h -# End Source File -# Begin Source File - -SOURCE=.\util.h -# End Source File -# Begin Source File - -SOURCE=.\vector.h -# End Source File -# Begin Source File - -SOURCE=.\weapons.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/sdk/dlls/hlgl.def b/sdk/dlls/hlgl.def deleted file mode 100644 index b94aa63..0000000 --- a/sdk/dlls/hlgl.def +++ /dev/null @@ -1,15 +0,0 @@ -LIBRARY hlgl -EXPORTS - GiveFnptrsToDll @1 - GetEntityInterfaces @2 - SetChangeParms @3 - SetNewParms @4 - ClientKill @5 - PutClientInServer @6 - PlayerPreThink @7 - PlayerPostThink @8 - ClientConnect @9 - ClientDisconnect @10 - StartFrame @11 -SECTIONS - .data READ WRITE diff --git a/sdk/dlls/hornet.cpp b/sdk/dlls/hornet.cpp deleted file mode 100644 index c9e43e3..0000000 --- a/sdk/dlls/hornet.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Hornets -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" -#include "hornet.h" -#include "gamerules.h" - - -int iHornetTrail; -int iHornetPuff; - -LINK_ENTITY_TO_CLASS( hornet, CHornet ); - -//========================================================= -// Save/Restore -//========================================================= -TYPEDESCRIPTION CHornet::m_SaveData[] = -{ - DEFINE_FIELD( CHornet, m_flStopAttack, FIELD_TIME ), - DEFINE_FIELD( CHornet, m_iHornetType, FIELD_INTEGER ), - DEFINE_FIELD( CHornet, m_flFlySpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CHornet, CBaseMonster ); - -//========================================================= -// don't let hornets gib, ever. -//========================================================= -int CHornet :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // filter these bits a little. - bitsDamageType &= ~ ( DMG_ALWAYSGIB ); - bitsDamageType |= DMG_NEVERGIB; - - return CBaseMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -//========================================================= -//========================================================= -void CHornet :: Spawn( void ) -{ - Precache(); - - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - pev->takedamage = DAMAGE_YES; - pev->flags |= FL_MONSTER; - pev->health = 1;// weak! - - if ( g_pGameRules->IsMultiplayer() ) - { - // hornets don't live as long in multiplayer - m_flStopAttack = gpGlobals->time + 3.5; - } - else - { - m_flStopAttack = gpGlobals->time + 5.0; - } - - m_flFieldOfView = 0.9; // +- 25 degrees - - if ( RANDOM_LONG ( 1, 5 ) <= 2 ) - { - m_iHornetType = HORNET_TYPE_RED; - m_flFlySpeed = HORNET_RED_SPEED; - } - else - { - m_iHornetType = HORNET_TYPE_ORANGE; - m_flFlySpeed = HORNET_ORANGE_SPEED; - } - - SET_MODEL(ENT( pev ), "models/hornet.mdl"); - UTIL_SetSize( pev, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ) ); - - SetTouch( &CHornet::DieTouch ); - SetThink( &CHornet::StartTrack ); - - edict_t *pSoundEnt = pev->owner; - if ( !pSoundEnt ) - pSoundEnt = edict(); - - if ( !FNullEnt(pev->owner) && (pev->owner->v.flags & FL_CLIENT) ) - { - pev->dmg = gSkillData.plrDmgHornet; - } - else - { - // no real owner, or owner isn't a client. - pev->dmg = gSkillData.monDmgHornet; - } - - pev->nextthink = gpGlobals->time + 0.1; - ResetSequenceInfo( ); -} - - -void CHornet :: Precache() -{ - PRECACHE_MODEL("models/hornet.mdl"); - - PRECACHE_SOUND( "agrunt/ag_fire1.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire2.wav" ); - PRECACHE_SOUND( "agrunt/ag_fire3.wav" ); - - PRECACHE_SOUND( "hornet/ag_buzz1.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz2.wav" ); - PRECACHE_SOUND( "hornet/ag_buzz3.wav" ); - - PRECACHE_SOUND( "hornet/ag_hornethit1.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit2.wav" ); - PRECACHE_SOUND( "hornet/ag_hornethit3.wav" ); - - iHornetPuff = PRECACHE_MODEL( "sprites/muz1.spr" ); - iHornetTrail = PRECACHE_MODEL("sprites/laserbeam.spr"); -} - -//========================================================= -// hornets will never get mad at each other, no matter who the owner is. -//========================================================= -int CHornet::IRelationship ( CBaseEntity *pTarget ) -{ - if ( pTarget->pev->modelindex == pev->modelindex ) - { - return R_NO; - } - - return CBaseMonster :: IRelationship( pTarget ); -} - -//========================================================= -// ID's Hornet as their owner -//========================================================= -int CHornet::Classify ( void ) -{ - - if ( pev->owner && pev->owner->v.flags & FL_CLIENT) - { - return CLASS_PLAYER_BIOWEAPON; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -//========================================================= -// StartTrack - starts a hornet out tracking its target -//========================================================= -void CHornet :: StartTrack ( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::TrackTouch ); - SetThink( &CHornet::TrackTarget ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// StartDart - starts a hornet out just flying straight. -//========================================================= -void CHornet :: StartDart ( void ) -{ - IgniteTrail(); - - SetTouch( &CHornet::DartTouch ); - - SetThink( &CHornet::SUB_Remove ); - pev->nextthink = gpGlobals->time + 4; -} - -void CHornet::IgniteTrail( void ) -{ -/* - - ted's suggested trail colors: - -r161 -g25 -b97 - -r173 -g39 -b14 - -old colors - case HORNET_TYPE_RED: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - break; - -*/ - - // trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT( entindex() ); // entity - WRITE_SHORT( iHornetTrail ); // model - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 2 ); // width - - switch ( m_iHornetType ) - { - case HORNET_TYPE_RED: - WRITE_BYTE( 179 ); // r, g, b - WRITE_BYTE( 39 ); // r, g, b - WRITE_BYTE( 14 ); // r, g, b - break; - case HORNET_TYPE_ORANGE: - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 0 ); // r, g, b - break; - } - - WRITE_BYTE( 128 ); // brightness - - MESSAGE_END(); -} - -//========================================================= -// Hornet is flying, gently tracking target -//========================================================= -void CHornet :: TrackTarget ( void ) -{ - Vector vecFlightDir; - Vector vecDirToEnemy; - float flDelta; - - StudioFrameAdvance( ); - - if (gpGlobals->time > m_flStopAttack) - { - SetTouch( NULL ); - SetThink( &CHornet::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - // UNDONE: The player pointer should come back after returning from another level - if ( m_hEnemy == 0 ) - {// enemy is dead. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if ( m_hEnemy != 0 && FVisible( m_hEnemy )) - { - m_vecEnemyLKP = m_hEnemy->BodyTarget( pev->origin ); - } - else - { - m_vecEnemyLKP = m_vecEnemyLKP + pev->velocity * m_flFlySpeed * 0.1; - } - - vecDirToEnemy = ( m_vecEnemyLKP - pev->origin ).Normalize(); - - if (pev->velocity.Length() < 0.1) - vecFlightDir = vecDirToEnemy; - else - vecFlightDir = pev->velocity.Normalize(); - - // measure how far the turn is, the wider the turn, the slow we'll go this time. - flDelta = DotProduct ( vecFlightDir, vecDirToEnemy ); - - if ( flDelta < 0.5 ) - {// hafta turn wide again. play sound - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - } - } - - if ( flDelta <= 0 && m_iHornetType == HORNET_TYPE_RED ) - {// no flying backwards, but we don't want to invert this, cause we'd go fast when we have to turn REAL far. - flDelta = 0.25; - } - - pev->velocity = ( vecFlightDir + vecDirToEnemy).Normalize(); - - if ( pev->owner && (pev->owner->v.flags & FL_MONSTER) ) - { - // random pattern only applies to hornets fired by monsters, not players. - - pev->velocity.x += RANDOM_FLOAT ( -0.10, 0.10 );// scramble the flight dir a bit. - pev->velocity.y += RANDOM_FLOAT ( -0.10, 0.10 ); - pev->velocity.z += RANDOM_FLOAT ( -0.10, 0.10 ); - } - - switch ( m_iHornetType ) - { - case HORNET_TYPE_RED: - pev->velocity = pev->velocity * ( m_flFlySpeed * flDelta );// scale the dir by the ( speed * width of turn ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); - break; - case HORNET_TYPE_ORANGE: - pev->velocity = pev->velocity * m_flFlySpeed;// do not have to slow down to turn. - pev->nextthink = gpGlobals->time + 0.1;// fixed think time - break; - } - - pev->angles = UTIL_VecToAngles (pev->velocity); - - pev->solid = SOLID_BBOX; - - // if hornet is close to the enemy, jet in a straight line for a half second. - // (only in the single player game) - if ( m_hEnemy != 0 && !g_pGameRules->IsMultiplayer() ) - { - if ( flDelta >= 0.4 && ( pev->origin - m_vecEnemyLKP ).Length() <= 300 ) - { - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( pev->origin.x); // pos - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_SHORT( iHornetPuff ); // model - // WRITE_BYTE( 0 ); // life * 10 - WRITE_BYTE( 2 ); // size * 10 - WRITE_BYTE( 128 ); // brightness - MESSAGE_END(); - - switch (RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz1.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz2.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_buzz3.wav", HORNET_BUZZ_VOLUME, ATTN_NORM); break; - } - pev->velocity = pev->velocity * 2; - pev->nextthink = gpGlobals->time + 1.0; - // don't attack again - m_flStopAttack = gpGlobals->time; - } - } -} - -//========================================================= -// Tracking Hornet hit something -//========================================================= -void CHornet :: TrackTouch ( CBaseEntity *pOther ) -{ - if ( pOther->edict() == pev->owner || pOther->pev->modelindex == pev->modelindex ) - {// bumped into the guy that shot it. - pev->solid = SOLID_NOT; - return; - } - - if ( IRelationship( pOther ) <= R_NO ) - { - // hit something we don't want to hurt, so turn around. - - pev->velocity = pev->velocity.Normalize(); - - pev->velocity.x *= -1; - pev->velocity.y *= -1; - - pev->origin = pev->origin + pev->velocity * 4; // bounce the hornet off a bit. - pev->velocity = pev->velocity * m_flFlySpeed; - - return; - } - - DieTouch( pOther ); -} - -void CHornet::DartTouch( CBaseEntity *pOther ) -{ - DieTouch( pOther ); -} - -void CHornet::DieTouch ( CBaseEntity *pOther ) -{ - if ( pOther && pOther->pev->takedamage ) - {// do the damage - - switch (RANDOM_LONG(0,2)) - {// buzz when you plug someone - case 0: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND( ENT(pev), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM); break; - } - - pOther->TakeDamage( pev, VARS( pev->owner ), pev->dmg, DMG_BULLET ); - } - - pev->modelindex = 0;// so will disappear for the 0.1 secs we wait until NEXTTHINK gets rid - pev->solid = SOLID_NOT; - - SetThink ( &CHornet::SUB_Remove ); - pev->nextthink = gpGlobals->time + 1;// stick around long enough for the sound to finish! -} - diff --git a/sdk/dlls/hornet.h b/sdk/dlls/hornet.h deleted file mode 100644 index 98d1710..0000000 --- a/sdk/dlls/hornet.h +++ /dev/null @@ -1,58 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Hornets -//========================================================= - -//========================================================= -// Hornet Defines -//========================================================= -#define HORNET_TYPE_RED 0 -#define HORNET_TYPE_ORANGE 1 -#define HORNET_RED_SPEED (float)600 -#define HORNET_ORANGE_SPEED (float)800 -#define HORNET_BUZZ_VOLUME (float)0.8 - -extern int iHornetPuff; - -//========================================================= -// Hornet - this is the projectile that the Alien Grunt fires. -//========================================================= -class CHornet : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - int IRelationship ( CBaseEntity *pTarget ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void IgniteTrail( void ); - void EXPORT StartTrack ( void ); - void EXPORT StartDart ( void ); - void EXPORT TrackTarget ( void ); - void EXPORT TrackTouch ( CBaseEntity *pOther ); - void EXPORT DartTouch( CBaseEntity *pOther ); - void EXPORT DieTouch ( CBaseEntity *pOther ); - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - float m_flStopAttack; - int m_iHornetType; - float m_flFlySpeed; -}; - diff --git a/sdk/dlls/hornetgun.cpp b/sdk/dlls/hornetgun.cpp deleted file mode 100644 index 0b16781..0000000 --- a/sdk/dlls/hornetgun.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "hornet.h" -#include "gamerules.h" - - -enum hgun_e { - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -enum firemode_e -{ - FIREMODE_TRACK = 0, - FIREMODE_FAST -}; - - -LINK_ENTITY_TO_CLASS( weapon_hornetgun, CHgun ); - -BOOL CHgun::IsUseable( void ) -{ - return TRUE; -} - -void CHgun::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_HORNETGUN; - SET_MODEL(ENT(pev), "models/w_hgun.mdl"); - - m_iDefaultAmmo = HIVEHAND_DEFAULT_GIVE; - m_iFirePhase = 0; - - FallInit();// get ready to fall down. -} - - -void CHgun::Precache( void ) -{ - PRECACHE_MODEL("models/v_hgun.mdl"); - PRECACHE_MODEL("models/w_hgun.mdl"); - PRECACHE_MODEL("models/p_hgun.mdl"); - - m_usHornetFire = PRECACHE_EVENT ( 1, "events/firehornet.sc" ); - - UTIL_PrecacheOther("hornet"); -} - -int CHgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - -#ifndef CLIENT_DLL - if ( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, all hivehands come full. - pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; - } -#endif - - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -int CHgun::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Hornets"; - p->iMaxAmmo1 = HORNET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 3; - p->iPosition = 3; - p->iId = m_iId = WEAPON_HORNETGUN; - p->iFlags = ITEM_FLAG_NOAUTOSWITCHEMPTY | ITEM_FLAG_NOAUTORELOAD; - p->iWeight = HORNETGUN_WEIGHT; - - return 1; -} - - -BOOL CHgun::Deploy( ) -{ - return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); -} - -void CHgun::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - SendWeaponAnim( HGUN_DOWN ); - - //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. - if ( !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ) - { - m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = 1; - } -} - - -void CHgun::PrimaryAttack() -{ - Reload( ); - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - { - return; - } - -#ifndef CLIENT_DLL - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - CBaseEntity *pHornet = CBaseEntity::Create( "hornet", m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 300; - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 ); - - - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = GetNextAttackDelay(0.25); - - if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - { - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; - } - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - - -void CHgun::SecondaryAttack( void ) -{ - Reload(); - - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - { - return; - } - - //Wouldn't be a bad idea to completely predict these, since they fly so fast... -#ifndef CLIENT_DLL - CBaseEntity *pHornet; - Vector vecSrc; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - - vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -12; - - m_iFirePhase++; - switch ( m_iFirePhase ) - { - case 1: - vecSrc = vecSrc + gpGlobals->v_up * 8; - break; - case 2: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 3: - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 4: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * 8; - break; - case 5: - vecSrc = vecSrc + gpGlobals->v_up * -8; - break; - case 6: - vecSrc = vecSrc + gpGlobals->v_up * -8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 7: - vecSrc = vecSrc + gpGlobals->v_right * -8; - break; - case 8: - vecSrc = vecSrc + gpGlobals->v_up * 8; - vecSrc = vecSrc + gpGlobals->v_right * -8; - m_iFirePhase = 0; - break; - } - - pHornet = CBaseEntity::Create( "hornet", vecSrc, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pHornet->pev->velocity = gpGlobals->v_forward * 1200; - pHornet->pev->angles = UTIL_VecToAngles( pHornet->pev->velocity ); - - pHornet->SetThink( &CHornet::StartDart ); - - m_flRechargeTime = gpGlobals->time + 0.5; -#endif - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); - - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CHgun::Reload( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY) - return; - - while (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] < HORNET_MAX_CARRY && m_flRechargeTime < gpGlobals->time) - { - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]++; - m_flRechargeTime += 0.5; - } -} - - -void CHgun::WeaponIdle( void ) -{ - Reload( ); - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); - } - else if (flRand <= 0.875) - { - iAnim = HGUN_FIDGETSWAY; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - else - { - iAnim = HGUN_FIDGETSHAKE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} - -#endif diff --git a/sdk/dlls/houndeye.cpp b/sdk/dlls/houndeye.cpp deleted file mode 100644 index 2c02729..0000000 --- a/sdk/dlls/houndeye.cpp +++ /dev/null @@ -1,1308 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Houndeye - spooky sonic dog. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "animation.h" -#include "nodes.h" -#include "squadmonster.h" -#include "soundent.h" -#include "game.h" - -extern CGraph WorldGraph; - -// houndeye does 20 points of damage spread over a sphere 384 units in diameter, and each additional -// squad member increases the BASE damage by 110%, per the spec. -#define HOUNDEYE_MAX_SQUAD_SIZE 4 -#define HOUNDEYE_MAX_ATTACK_RADIUS 384 -#define HOUNDEYE_SQUAD_BONUS (float)1.1 - -#define HOUNDEYE_EYE_FRAMES 4 // how many different switchable maps for the eye - -#define HOUNDEYE_SOUND_STARTLE_VOLUME 128 // how loud a sound has to be to badly scare a sleeping houndeye - -//========================================================= -// monster-specific tasks -//========================================================= -enum -{ - TASK_HOUND_CLOSE_EYE = LAST_COMMON_TASK + 1, - TASK_HOUND_OPEN_EYE, - TASK_HOUND_THREAT_DISPLAY, - TASK_HOUND_FALL_ASLEEP, - TASK_HOUND_WAKE_UP, - TASK_HOUND_HOP_BACK -}; - -//========================================================= -// monster-specific schedule types -//========================================================= -enum -{ - SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1, - SCHED_HOUND_HOP_RETREAT, - SCHED_HOUND_FAIL, -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define HOUND_AE_WARN 1 -#define HOUND_AE_STARTATTACK 2 -#define HOUND_AE_THUMP 3 -#define HOUND_AE_ANGERSOUND1 4 -#define HOUND_AE_ANGERSOUND2 5 -#define HOUND_AE_HOPBACK 6 -#define HOUND_AE_CLOSE_EYE 7 - -class CHoundeye : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void SetYawSpeed ( void ); - void WarmUpSound ( void ); - void AlertSound( void ); - void DeathSound( void ); - void WarnSound( void ); - void PainSound( void ); - void IdleSound( void ); - void StartTask( Task_t *pTask ); - void RunTask ( Task_t *pTask ); - void SonicAttack( void ); - void PrescheduleThink( void ); - void SetActivity ( Activity NewActivity ); - void WriteBeamColor ( void ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL FValidateHintType ( short sHint ); - BOOL FCanActiveIdle ( void ); - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule( void ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - CUSTOM_SCHEDULES; - static TYPEDESCRIPTION m_SaveData[]; - - int m_iSpriteTexture; - BOOL m_fAsleep;// some houndeyes sleep in idle mode if this is set, the houndeye is lying down - BOOL m_fDontBlink;// don't try to open/close eye if this bit is set! - Vector m_vecPackCenter; // the center of the pack. The leader maintains this by averaging the origins of all pack members. -}; -LINK_ENTITY_TO_CLASS( monster_houndeye, CHoundeye ); - -TYPEDESCRIPTION CHoundeye::m_SaveData[] = -{ - DEFINE_FIELD( CHoundeye, m_iSpriteTexture, FIELD_INTEGER ), - DEFINE_FIELD( CHoundeye, m_fAsleep, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_fDontBlink, FIELD_BOOLEAN ), - DEFINE_FIELD( CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CHoundeye, CSquadMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CHoundeye :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// FValidateHintType -//========================================================= -BOOL CHoundeye :: FValidateHintType ( short sHint ) -{ - size_t i; - - static short sHoundHints[] = - { - HINT_WORLD_MACHINERY, - HINT_WORLD_BLINKING_LIGHT, - HINT_WORLD_HUMAN_BLOOD, - HINT_WORLD_ALIEN_BLOOD, - }; - - for ( i = 0 ; i < ARRAYSIZE ( sHoundHints ) ; i++ ) - { - if ( sHoundHints[ i ] == sHint ) - { - return TRUE; - } - } - - ALERT ( at_aiconsole, "Couldn't validate hint type" ); - return FALSE; -} - - -//========================================================= -// FCanActiveIdle -//========================================================= -BOOL CHoundeye :: FCanActiveIdle ( void ) -{ - if ( InSquad() ) - { - CSquadMonster *pSquadLeader = MySquadLeader(); - - for (int i = 0; i < MAX_SQUAD_MEMBERS;i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - - if ( pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE ) - { - // someone else in the group is active idling right now! - return FALSE; - } - } - - return TRUE; - } - - return TRUE; -} - - -//========================================================= -// CheckRangeAttack1 - overridden for houndeyes so that they -// try to get within half of their max attack radius before -// attacking, so as to increase their chances of doing damage. -//========================================================= -BOOL CHoundeye :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist <= ( HOUNDEYE_MAX_ATTACK_RADIUS * 0.5 ) && flDot >= 0.3 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CHoundeye :: SetYawSpeed ( void ) -{ - int ys; - - ys = 90; - - switch ( m_Activity ) - { - case ACT_CROUCHIDLE://sleeping! - ys = 0; - break; - case ACT_IDLE: - ys = 60; - break; - case ACT_WALK: - ys = 90; - break; - case ACT_RUN: - ys = 90; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 90; - break; - default: - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// SetActivity -//========================================================= -void CHoundeye :: SetActivity ( Activity NewActivity ) -{ - int iSequence; - - if ( NewActivity == m_Activity ) - return; - - if ( m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG(0,1) ) - { - // play pissed idle. - iSequence = LookupSequence( "madidle" ); - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = iSequence; // Set to the reset anim (if it's there) - pev->frame = 0; // FIX: frame counter shouldn't be reset when its the same activity as before - ResetSequenceInfo(); - SetYawSpeed(); - } - } - else - { - CSquadMonster :: SetActivity ( NewActivity ); - } -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CHoundeye :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch ( pEvent->event ) - { - case HOUND_AE_WARN: - // do stuff for this event. - WarnSound(); - break; - - case HOUND_AE_STARTATTACK: - WarmUpSound(); - break; - - case HOUND_AE_HOPBACK: - { - float flGravity = g_psv_gravity->value; - - pev->flags &= ~FL_ONGROUND; - - pev->velocity = gpGlobals->v_forward * -200; - pev->velocity.z += (0.6 * flGravity) * 0.5; - - break; - } - - case HOUND_AE_THUMP: - // emit the shockwaves - SonicAttack(); - break; - - case HOUND_AE_ANGERSOUND1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM); - break; - - case HOUND_AE_ANGERSOUND2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM); - break; - - case HOUND_AE_CLOSE_EYE: - if ( !m_fDontBlink ) - { - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CHoundeye :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/houndeye.mdl"); - UTIL_SetSize(pev, Vector ( -16, -16, 0 ), Vector ( 16, 16, 36 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = gSkillData.houndeyeHealth; - pev->yaw_speed = 5;//!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim? - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_fAsleep = FALSE; // everyone spawns awake - m_fDontBlink = FALSE; - m_afCapability |= bits_CAP_SQUAD; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CHoundeye :: Precache() -{ - PRECACHE_MODEL("models/houndeye.mdl"); - - PRECACHE_SOUND("houndeye/he_alert1.wav"); - PRECACHE_SOUND("houndeye/he_alert2.wav"); - PRECACHE_SOUND("houndeye/he_alert3.wav"); - - PRECACHE_SOUND("houndeye/he_die1.wav"); - PRECACHE_SOUND("houndeye/he_die2.wav"); - PRECACHE_SOUND("houndeye/he_die3.wav"); - - PRECACHE_SOUND("houndeye/he_idle1.wav"); - PRECACHE_SOUND("houndeye/he_idle2.wav"); - PRECACHE_SOUND("houndeye/he_idle3.wav"); - - PRECACHE_SOUND("houndeye/he_hunt1.wav"); - PRECACHE_SOUND("houndeye/he_hunt2.wav"); - PRECACHE_SOUND("houndeye/he_hunt3.wav"); - - PRECACHE_SOUND("houndeye/he_pain1.wav"); - PRECACHE_SOUND("houndeye/he_pain3.wav"); - PRECACHE_SOUND("houndeye/he_pain4.wav"); - PRECACHE_SOUND("houndeye/he_pain5.wav"); - - PRECACHE_SOUND("houndeye/he_attack1.wav"); - PRECACHE_SOUND("houndeye/he_attack3.wav"); - - PRECACHE_SOUND("houndeye/he_blast1.wav"); - PRECACHE_SOUND("houndeye/he_blast2.wav"); - PRECACHE_SOUND("houndeye/he_blast3.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/shockwave.spr" ); -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye :: IdleSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// IdleSound -//========================================================= -void CHoundeye :: WarmUpSound ( void ) -{ - switch ( RANDOM_LONG(0,1) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM ); - break; - } -} - -//========================================================= -// WarnSound -//========================================================= -void CHoundeye :: WarnSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CHoundeye :: AlertSound ( void ) -{ - - if ( InSquad() && !IsLeader() ) - { - return; // only leader makes ALERT sound. - } - - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CHoundeye :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die2.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CHoundeye :: PainSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM ); - break; - } -} - -//========================================================= -// WriteBeamColor - writes a color vector to the network -// based on the size of the group. -//========================================================= -void CHoundeye :: WriteBeamColor ( void ) -{ - BYTE bRed, bGreen, bBlue; - - if ( InSquad() ) - { - switch ( SquadCount() ) - { - case 2: - // no case for 0 or 1, cause those are impossible for monsters in Squads. - bRed = 101; - bGreen = 133; - bBlue = 221; - break; - case 3: - bRed = 67; - bGreen = 85; - bBlue = 255; - break; - case 4: - bRed = 62; - bGreen = 33; - bBlue = 211; - break; - default: - ALERT ( at_aiconsole, "Unsupported Houndeye SquadSize!\n" ); - bRed = 188; - bGreen = 220; - bBlue = 255; - break; - } - } - else - { - // solo houndeye - weakest beam - bRed = 188; - bGreen = 220; - bBlue = 255; - } - - WRITE_BYTE( bRed ); - WRITE_BYTE( bGreen ); - WRITE_BYTE( bBlue ); -} - - -//========================================================= -// SonicAttack -//========================================================= -void CHoundeye :: SonicAttack ( void ) -{ - float flAdjustedDamage; - float flDist; - - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM); break; - } - - // blast circles - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16 + ( HOUNDEYE_MAX_ATTACK_RADIUS / 2 ) / .2); // reach damage radius over .3 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - - WriteBeamColor(); - - WRITE_BYTE( 255 ); //brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - - CBaseEntity *pEntity = NULL; - // iterate on all entities in the vicinity. - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS )) != NULL) - { - if ( pEntity->pev->takedamage != DAMAGE_NO ) - { - if ( !FClassnameIs(pEntity->pev, "monster_houndeye") ) - {// houndeyes don't hurt other houndeyes with their attack - - // houndeyes do FULL damage if the ent in question is visible. Half damage otherwise. - // This means that you must get out of the houndeye's attack range entirely to avoid damage. - // Calculate full damage first - - if ( SquadCount() > 1 ) - { - // squad gets attack bonus. - flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * ( HOUNDEYE_SQUAD_BONUS * ( SquadCount() - 1 ) ); - } - else - { - // solo - flAdjustedDamage = gSkillData.houndeyeDmgBlast; - } - - flDist = (pEntity->Center() - pev->origin).Length(); - - flAdjustedDamage -= ( flDist / HOUNDEYE_MAX_ATTACK_RADIUS ) * flAdjustedDamage; - - if ( !FVisible( pEntity ) ) - { - if ( pEntity->IsPlayer() ) - { - // if this entity is a client, and is not in full view, inflict half damage. We do this so that players still - // take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients - // so that monsters in other parts of the level don't take the damage and get pissed. - flAdjustedDamage *= 0.5; - } - else if ( !FClassnameIs( pEntity->pev, "func_breakable" ) && !FClassnameIs( pEntity->pev, "func_pushable" ) ) - { - // do not hurt nonclients through walls, but allow damage to be done to breakables - flAdjustedDamage = 0; - } - } - - //ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage ); - - if (flAdjustedDamage > 0 ) - { - pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB ); - } - } - } - } -} - -//========================================================= -// start task -//========================================================= -void CHoundeye :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_HOUND_FALL_ASLEEP: - { - m_fAsleep = TRUE; // signal that hound is lying down (must stand again before doing anything else!) - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_WAKE_UP: - { - m_fAsleep = FALSE; // signal that hound is standing again - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_OPEN_EYE: - { - m_fDontBlink = FALSE; // turn blinking back on and that code will automatically open the eye - m_iTaskStatus = TASKSTATUS_COMPLETE; - break; - } - case TASK_HOUND_CLOSE_EYE: - { - pev->skin = 0; - m_fDontBlink = TRUE; // tell blink code to leave the eye alone. - break; - } - case TASK_HOUND_THREAT_DISPLAY: - { - m_IdealActivity = ACT_IDLE_ANGRY; - break; - } - case TASK_HOUND_HOP_BACK: - { - m_IdealActivity = ACT_LEAP; - break; - } - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - -/* - if ( InSquad() ) - { - // see if there is a battery to connect to. - CSquadMonster *pSquad = m_pSquadLeader; - - while ( pSquad ) - { - if ( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY ) - { - // draw a beam. - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( ENTINDEX( this->edict() ) ); - WRITE_SHORT( ENTINDEX( pSquad->edict() ) ); - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 10 ); // noise - WRITE_BYTE( 0 ); // r, g, b - WRITE_BYTE( 50 ); // r, g, b - WRITE_BYTE( 250); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - break; - } - - pSquad = pSquad->m_pSquadNext; - } - } -*/ - - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_GUARD: - { - m_IdealActivity = ACT_GUARD; - break; - } - default: - { - CSquadMonster :: StartTask(pTask); - break; - } - } -} - -//========================================================= -// RunTask -//========================================================= -void CHoundeye :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_HOUND_THREAT_DISPLAY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - - break; - } - case TASK_HOUND_CLOSE_EYE: - { - if ( pev->skin < HOUNDEYE_EYE_FRAMES - 1 ) - { - pev->skin++; - } - break; - } - case TASK_HOUND_HOP_BACK: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - case TASK_SPECIAL_ATTACK1: - { - pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1); - - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - float life; - life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate)); - if (life < 0.1) life = 0.1; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_IMPLOSION); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 16); - WRITE_BYTE( 50 * life + 100); // radius - WRITE_BYTE( pev->frame / 25.0 ); // count - WRITE_BYTE( life * 10 ); // life - MESSAGE_END(); - - if ( m_fSequenceFinished ) - { - SonicAttack(); - TaskComplete(); - } - - break; - } - default: - { - CSquadMonster :: RunTask(pTask); - break; - } - } -} - -//========================================================= -// PrescheduleThink -//========================================================= -void CHoundeye::PrescheduleThink ( void ) -{ - // if the hound is mad and is running, make hunt noises. - if ( m_MonsterState == MONSTERSTATE_COMBAT && m_Activity == ACT_RUN && RANDOM_FLOAT( 0, 1 ) < 0.2 ) - { - WarnSound(); - } - - // at random, initiate a blink if not already blinking or sleeping - if ( !m_fDontBlink ) - { - if ( ( pev->skin == 0 ) && RANDOM_LONG(0,0x7F) == 0 ) - {// start blinking! - pev->skin = HOUNDEYE_EYE_FRAMES - 1; - } - else if ( pev->skin != 0 ) - {// already blinking - pev->skin--; - } - } - - // if you are the leader, average the origins of each pack member to get an approximate center. - if ( IsLeader() ) - { - CSquadMonster *pSquadMember; - int iSquadCount = 0; - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - pSquadMember = MySquadMember(i); - - if (pSquadMember) - { - iSquadCount++; - m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin; - } - } - - m_vecPackCenter = m_vecPackCenter / iSquadCount; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlHoundGuardPack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_GUARD, (float)0 }, -}; - -Schedule_t slHoundGuardPack[] = -{ - { - tlHoundGuardPack, - ARRAYSIZE ( tlHoundGuardPack ), - bits_COND_SEE_HATE | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_PROVOKED | - bits_COND_HEAR_SOUND, - - bits_SOUND_COMBAT |// sound flags - bits_SOUND_WORLD | - bits_SOUND_MEAT | - bits_SOUND_PLAYER, - "GuardPack" - }, -}; - -// primary range attack -Task_t tlHoundYell1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_HOUND_AGITATED }, -}; - -Task_t tlHoundYell2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slHoundRangeAttack[] = -{ - { - tlHoundYell1, - ARRAYSIZE ( tlHoundYell1 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack1" - }, - { - tlHoundYell2, - ARRAYSIZE ( tlHoundYell2 ), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundRangeAttack2" - }, -}; - -// lie down and fall asleep -Task_t tlHoundSleep[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_RANDOM, (float)5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_HOUND_FALL_ASLEEP, (float)0 }, - { TASK_WAIT_RANDOM, (float)25 }, - { TASK_HOUND_CLOSE_EYE, (float)0 }, - //{ TASK_WAIT, (float)10 }, - //{ TASK_WAIT_RANDOM, (float)10 }, -}; - -Schedule_t slHoundSleep[] = -{ - { - tlHoundSleep, - ARRAYSIZE ( tlHoundSleep ), - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_NEW_ENEMY, - - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_WORLD, - "Hound Sleep" - }, -}; - -// wake and stand up lazily -Task_t tlHoundWakeLazy[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_WAIT_RANDOM, (float)2.5 }, - { TASK_PLAY_SEQUENCE, (float)ACT_STAND }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeLazy[] = -{ - { - tlHoundWakeLazy, - ARRAYSIZE ( tlHoundWakeLazy ), - 0, - 0, - "WakeLazy" - }, -}; - -// wake and stand up with great urgency! -Task_t tlHoundWakeUrgent[] = -{ - { TASK_HOUND_OPEN_EYE, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_HOP }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_HOUND_WAKE_UP, (float)0 }, -}; - -Schedule_t slHoundWakeUrgent[] = -{ - { - tlHoundWakeUrgent, - ARRAYSIZE ( tlHoundWakeUrgent ), - 0, - 0, - "WakeUrgent" - }, -}; - - -Task_t tlHoundSpecialAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SPECIAL_ATTACK1, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_IDLE_ANGRY }, -}; - -Schedule_t slHoundSpecialAttack1[] = -{ - { - tlHoundSpecialAttack1, - ARRAYSIZE ( tlHoundSpecialAttack1 ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED, - - 0, - "Hound Special Attack1" - }, -}; - -Task_t tlHoundAgitated[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, -}; - -Schedule_t slHoundAgitated[] = -{ - { - tlHoundAgitated, - ARRAYSIZE ( tlHoundAgitated ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Hound Agitated" - }, -}; - -Task_t tlHoundHopRetreat[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_HOP_BACK, 0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slHoundHopRetreat[] = -{ - { - tlHoundHopRetreat, - ARRAYSIZE ( tlHoundHopRetreat ), - 0, - 0, - "Hound Hop Retreat" - }, -}; - -// hound fails in combat with client in the PVS -Task_t tlHoundCombatFailPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slHoundCombatFailPVS[] = -{ - { - tlHoundCombatFailPVS, - ARRAYSIZE ( tlHoundCombatFailPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailPVS" - }, -}; - -// hound fails in combat with no client in the PVS. Don't keep peeping! -Task_t tlHoundCombatFailNoPVS[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_HOUND_THREAT_DISPLAY, 0 }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_PVS, 0 }, -}; - -Schedule_t slHoundCombatFailNoPVS[] = -{ - { - tlHoundCombatFailNoPVS, - ARRAYSIZE ( tlHoundCombatFailNoPVS ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "HoundCombatFailNoPVS" - }, -}; - -DEFINE_CUSTOM_SCHEDULES( CHoundeye ) -{ - slHoundGuardPack, - slHoundRangeAttack, - &slHoundRangeAttack[ 1 ], - slHoundSleep, - slHoundWakeLazy, - slHoundWakeUrgent, - slHoundSpecialAttack1, - slHoundAgitated, - slHoundHopRetreat, - slHoundCombatFailPVS, - slHoundCombatFailNoPVS, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CHoundeye, CSquadMonster ); - -//========================================================= -// GetScheduleOfType -//========================================================= -Schedule_t* CHoundeye :: GetScheduleOfType ( int Type ) -{ - if ( m_fAsleep ) - { - // if the hound is sleeping, must wake and stand! - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pWakeSound; - - pWakeSound = PBestSound(); - ASSERT( pWakeSound != NULL ); - if ( pWakeSound ) - { - MakeIdealYaw ( pWakeSound->m_vecOrigin ); - - if ( FLSoundVolume ( pWakeSound ) >= HOUNDEYE_SOUND_STARTLE_VOLUME ) - { - // awakened by a loud sound - return &slHoundWakeUrgent[ 0 ]; - } - } - // sound was not loud enough to scare the bejesus out of houndeye - return &slHoundWakeLazy[ 0 ]; - } - else if ( HasConditions( bits_COND_NEW_ENEMY ) ) - { - // get up fast, to fight. - return &slHoundWakeUrgent[ 0 ]; - } - - else - { - // hound is waking up on its own - return &slHoundWakeLazy[ 0 ]; - } - } - switch ( Type ) - { - case SCHED_IDLE_STAND: - { - // we may want to sleep instead of stand! - if ( InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0,29) < 1 ) - { - return &slHoundSleep[ 0 ]; - } - else - { - return CSquadMonster :: GetScheduleOfType( Type ); - } - } - case SCHED_RANGE_ATTACK1: - { - return &slHoundRangeAttack[ 0 ]; -/* - if ( InSquad() ) - { - return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ]; - } - - return &slHoundRangeAttack[ 1 ]; -*/ - } - case SCHED_SPECIAL_ATTACK1: - { - return &slHoundSpecialAttack1[ 0 ]; - } - case SCHED_GUARD: - { - return &slHoundGuardPack[ 0 ]; - } - case SCHED_HOUND_AGITATED: - { - return &slHoundAgitated[ 0 ]; - } - case SCHED_HOUND_HOP_RETREAT: - { - return &slHoundHopRetreat[ 0 ]; - } - case SCHED_FAIL: - { - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - // client in PVS - return &slHoundCombatFailPVS[ 0 ]; - } - else - { - // client has taken off! - return &slHoundCombatFailNoPVS[ 0 ]; - } - } - else - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t *CHoundeye :: GetSchedule( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - { -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - if ( RANDOM_FLOAT( 0 , 1 ) <= 0.4 ) - { - TraceResult tr; - UTIL_MakeVectors( pev->angles ); - UTIL_TraceHull( pev->origin, pev->origin + gpGlobals->v_forward * -128, dont_ignore_monsters, head_hull, ENT( pev ), &tr ); - - if ( tr.flFraction == 1.0 ) - { - // it's clear behind, so the hound will jump - return GetScheduleOfType ( SCHED_HOUND_HOP_RETREAT ); - } - } - - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if ( OccupySlot ( bits_SLOTS_HOUND_ATTACK ) ) - { - return GetScheduleOfType ( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_HOUND_AGITATED ); - } - break; - } - default: - break; - } - - return CSquadMonster :: GetSchedule(); -} diff --git a/sdk/dlls/ichthyosaur.cpp b/sdk/dlls/ichthyosaur.cpp deleted file mode 100644 index 50e2ef6..0000000 --- a/sdk/dlls/ichthyosaur.cpp +++ /dev/null @@ -1,1108 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -//========================================================= -// icthyosaur - evin, satan fish monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "flyingmonster.h" -#include "nodes.h" -#include "soundent.h" -#include "animation.h" -#include "effects.h" -#include "weapons.h" - -#define SEARCH_RETRY 16 - -#define ICHTHYOSAUR_SPEED 150 - -extern CGraph WorldGraph; - -#define EYE_MAD 0 -#define EYE_BASE 1 -#define EYE_CLOSED 2 -#define EYE_BACK 3 -#define EYE_LOOK 4 - - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -// UNDONE: Save/restore here -class CIchthyosaur : public CFlyingMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - - void Killed( entvars_t *pevAttacker, int iGib ); - void BecomeDead( void ); - - void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT BiteTouch( CBaseEntity *pOther ); - - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - - BOOL CheckMeleeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - - float ChangeYaw( int speed ); - Activity GetStoppedActivity( void ); - - void Move( float flInterval ); - void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); - void MonsterThink( void ); - void Stop( void ); - void Swim( void ); - Vector DoProbe(const Vector &Probe); - - float VectorToPitch( const Vector &vec); - float FlPitchDiff( void ); - float ChangePitch( int speed ); - - Vector m_SaveVelocity; - float m_idealDist; - - float m_flBlink; - - float m_flEnemyTouched; - BOOL m_bOnAttack; - - float m_flMaxSpeed; - float m_flMinSpeed; - float m_flMaxDist; - - CBeam *m_pBeam; - - float m_flNextAlert; - - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pAttackSounds[]; - static const char *pBiteSounds[]; - static const char *pDieSounds[]; - static const char *pPainSounds[]; - - void IdleSound( void ); - void AlertSound( void ); - void AttackSound( void ); - void BiteSound( void ); - void DeathSound( void ); - void PainSound( void ); -}; - -LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur ); - -TYPEDESCRIPTION CIchthyosaur::m_SaveData[] = -{ - DEFINE_FIELD( CIchthyosaur, m_SaveVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CIchthyosaur, m_idealDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flBlink, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flEnemyTouched, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_bOnAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CIchthyosaur, m_flMaxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMinSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flMaxDist, FIELD_FLOAT ), - DEFINE_FIELD( CIchthyosaur, m_flNextAlert, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CIchthyosaur, CFlyingMonster ); - - -const char *CIchthyosaur::pIdleSounds[] = -{ - "ichy/ichy_idle1.wav", - "ichy/ichy_idle2.wav", - "ichy/ichy_idle3.wav", - "ichy/ichy_idle4.wav", -}; - -const char *CIchthyosaur::pAlertSounds[] = -{ - "ichy/ichy_alert2.wav", - "ichy/ichy_alert3.wav", -}; - -const char *CIchthyosaur::pAttackSounds[] = -{ - "ichy/ichy_attack1.wav", - "ichy/ichy_attack2.wav", -}; - -const char *CIchthyosaur::pBiteSounds[] = -{ - "ichy/ichy_bite1.wav", - "ichy/ichy_bite2.wav", -}; - -const char *CIchthyosaur::pPainSounds[] = -{ - "ichy/ichy_pain2.wav", - "ichy/ichy_pain3.wav", - "ichy/ichy_pain5.wav", -}; - -const char *CIchthyosaur::pDieSounds[] = -{ - "ichy/ichy_die2.wav", - "ichy/ichy_die4.wav", -}; - -#define EMIT_ICKY_SOUND( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, 0.6, 0, RANDOM_LONG(95,105) ); - - -void CIchthyosaur :: IdleSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); -} - -void CIchthyosaur :: AlertSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); -} - -void CIchthyosaur :: AttackSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); -} - -void CIchthyosaur :: BiteSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); -} - -void CIchthyosaur :: DeathSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); -} - -void CIchthyosaur :: PainSound( void ) -{ - EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); -} - -//========================================================= -// monster-specific tasks and states -//========================================================= -enum -{ - TASK_ICHTHYOSAUR_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, - TASK_ICHTHYOSAUR_SWIM, - TASK_ICHTHYOSAUR_FLOAT, -}; - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -static Task_t tlSwimAround[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_SWIM, 0.0 }, -}; - -static Schedule_t slSwimAround[] = -{ - { - tlSwimAround, - ARRAYSIZE(tlSwimAround), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_PLAYER | - bits_SOUND_COMBAT, - "SwimAround" - }, -}; - -static Task_t tlSwimAgitated[] = -{ - { TASK_STOP_MOVING, (float) 0 }, - { TASK_SET_ACTIVITY, (float)ACT_RUN }, - { TASK_WAIT, (float)2.0 }, -}; - -static Schedule_t slSwimAgitated[] = -{ - { - tlSwimAgitated, - ARRAYSIZE(tlSwimAgitated), - 0, - 0, - "SwimAgitated" - }, -}; - - -static Task_t tlCircleEnemy[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ICHTHYOSAUR_CIRCLE_ENEMY, 0.0 }, -}; - -static Schedule_t slCircleEnemy[] = -{ - { - tlCircleEnemy, - ARRAYSIZE(tlCircleEnemy), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK1, - 0, - "CircleEnemy" - }, -}; - - -Task_t tlTwitchDie[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, - { TASK_ICHTHYOSAUR_FLOAT, (float)0 }, -}; - -Schedule_t slTwitchDie[] = -{ - { - tlTwitchDie, - ARRAYSIZE( tlTwitchDie ), - 0, - 0, - "Die" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES(CIchthyosaur) -{ - slSwimAround, - slSwimAgitated, - slCircleEnemy, - slTwitchDie, -}; -IMPLEMENT_CUSTOM_SCHEDULES(CIchthyosaur, CFlyingMonster); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CIchthyosaur :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CIchthyosaur :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) - { - return TRUE; - } - return FALSE; -} - -void CIchthyosaur::BiteTouch( CBaseEntity *pOther ) -{ - // bite if we hit who we want to eat - if ( pOther == m_hEnemy ) - { - m_flEnemyTouched = gpGlobals->time; - m_bOnAttack = TRUE; - } -} - -void CIchthyosaur::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_bOnAttack ) ) - return; - - if (m_bOnAttack) - { - m_bOnAttack = 0; - } - else - { - m_bOnAttack = 1; - } -} - -//========================================================= -// CheckRangeAttack1 - swim in for a chomp -// -//========================================================= -BOOL CIchthyosaur :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192))) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CIchthyosaur :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 100; -} - - - -//========================================================= -// Killed - overrides CFlyingMonster. -// -void CIchthyosaur :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); - pev->velocity = Vector( 0, 0, 0 ); -} - -void CIchthyosaur::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. -} - -#define ICHTHYOSAUR_AE_SHAKE_RIGHT 1 -#define ICHTHYOSAUR_AE_SHAKE_LEFT 2 - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - int bDidAttack = FALSE; - switch( pEvent->event ) - { - case ICHTHYOSAUR_AE_SHAKE_RIGHT: - case ICHTHYOSAUR_AE_SHAKE_LEFT: - { - if (m_hEnemy != 0 && FVisible( m_hEnemy )) - { - CBaseEntity *pHurt = m_hEnemy; - - if (m_flEnemyTouched < gpGlobals->time - 0.2 && (m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > (32+16+32)) - break; - - Vector vecShootDir = ShootAtEnemy( pev->origin ); - UTIL_MakeAimVectors ( pev->angles ); - - if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707) - { - m_bOnAttack = TRUE; - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300; - if (pHurt->IsPlayer()) - { - pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); - pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); - pHurt->pev->angles.z = 0; - pHurt->pev->fixangle = TRUE; - } - pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH ); - } - } - BiteSound(); - - bDidAttack = TRUE; - } - break; - default: - CFlyingMonster::HandleAnimEvent( pEvent ); - break; - } - - if (bDidAttack) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; - UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CIchthyosaur :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/icky.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.ichthyosaurHealth; - pev->view_ofs = Vector ( 0, 0, 16 ); - m_flFieldOfView = VIEW_FIELD_WIDE; - m_MonsterState = MONSTERSTATE_NONE; - SetBits(pev->flags, FL_SWIM); - SetFlyingSpeed( ICHTHYOSAUR_SPEED ); - SetFlyingMomentum( 2.5 ); // Set momentum constant - - m_afCapability = bits_CAP_RANGE_ATTACK1 | bits_CAP_SWIM; - - MonsterInit(); - - SetTouch( &CIchthyosaur::BiteTouch ); - SetUse( &CIchthyosaur::CombatUse ); - - m_idealDist = 384; - m_flMinSpeed = 80; - m_flMaxSpeed = 300; - m_flMaxDist = 384; - - Vector Forward; - UTIL_MakeVectorsPrivate(pev->angles, Forward, 0, 0); - pev->velocity = m_flightSpeed * Forward.Normalize(); - m_SaveVelocity = pev->velocity; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CIchthyosaur :: Precache() -{ - PRECACHE_MODEL("models/icky.mdl"); - - PRECACHE_SOUND_ARRAY( pIdleSounds ); - PRECACHE_SOUND_ARRAY( pAlertSounds ); - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBiteSounds ); - PRECACHE_SOUND_ARRAY( pDieSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); -} - -//========================================================= -// GetSchedule -//========================================================= -Schedule_t* CIchthyosaur::GetSchedule() -{ - // ALERT( at_console, "GetSchedule( )\n" ); - switch(m_MonsterState) - { - case MONSTERSTATE_IDLE: - m_flightSpeed = 80; - return GetScheduleOfType( SCHED_IDLE_WALK ); - - case MONSTERSTATE_ALERT: - m_flightSpeed = 150; - return GetScheduleOfType( SCHED_IDLE_WALK ); - - case MONSTERSTATE_COMBAT: - m_flMaxSpeed = 400; - // eat them - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - // chase them down and eat them - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) - { - m_bOnAttack = TRUE; - } - if ( pev->health < pev->max_health - 20 ) - { - m_bOnAttack = TRUE; - } - - return GetScheduleOfType( SCHED_STANDOFF ); - default: - break; - } - - return CFlyingMonster :: GetSchedule(); -} - - -//========================================================= -//========================================================= -Schedule_t* CIchthyosaur :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); - switch ( Type ) - { - case SCHED_IDLE_WALK: - return slSwimAround; - case SCHED_STANDOFF: - return slCircleEnemy; - case SCHED_FAIL: - return slSwimAgitated; - case SCHED_DIE: - return slTwitchDie; - case SCHED_CHASE_ENEMY: - AttackSound( ); - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - - - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CIchthyosaur::StartTask(Task_t *pTask) -{ - switch (pTask->iTask) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - break; - case TASK_ICHTHYOSAUR_SWIM: - break; - case TASK_SMALL_FLINCH: - if (m_idealDist > 128) - { - m_flMaxDist = 512; - m_idealDist = 512; - } - else - { - m_bOnAttack = TRUE; - } - CFlyingMonster::StartTask(pTask); - break; - - case TASK_ICHTHYOSAUR_FLOAT: - pev->skin = EYE_BASE; - SetSequenceByName( "bellyup" ); - break; - - default: - CFlyingMonster::StartTask(pTask); - break; - } -} - -void CIchthyosaur :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_ICHTHYOSAUR_CIRCLE_ENEMY: - if (m_hEnemy == 0) - { - TaskComplete( ); - } - else if (FVisible( m_hEnemy )) - { - Vector vecFrom = m_hEnemy->EyePosition( ); - - Vector vecDelta = (pev->origin - vecFrom).Normalize( ); - Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize( ); - - if (DotProduct( vecSwim, m_SaveVelocity ) < 0) - vecSwim = vecSwim * -1.0; - - Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; - - // ALERT( at_console, "vecPos %.0f %.0f %.0f\n", vecPos.x, vecPos.y, vecPos.z ); - - TraceResult tr; - - UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); - - if (tr.flFraction > 0.5) - vecPos = tr.vecEndPos; - - m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * (vecPos - pev->origin).Normalize() * m_flightSpeed; - - // ALERT( at_console, "m_SaveVelocity %.2f %.2f %.2f\n", m_SaveVelocity.x, m_SaveVelocity.y, m_SaveVelocity.z ); - - if (HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this )) - { - m_flNextAlert -= 0.1; - - if (m_idealDist < m_flMaxDist) - { - m_idealDist += 4; - } - if (m_flightSpeed > m_flMinSpeed) - { - m_flightSpeed -= 2; - } - else if (m_flightSpeed < m_flMinSpeed) - { - m_flightSpeed += 2; - } - if (m_flMinSpeed < m_flMaxSpeed) - { - m_flMinSpeed += 0.5; - } - } - else - { - m_flNextAlert += 0.1; - - if (m_idealDist > 128) - { - m_idealDist -= 4; - } - if (m_flightSpeed < m_flMaxSpeed) - { - m_flightSpeed += 4; - } - } - // ALERT( at_console, "%.0f\n", m_idealDist ); - } - else - { - m_flNextAlert = gpGlobals->time + 0.2; - } - - if (m_flNextAlert < gpGlobals->time) - { - // ALERT( at_console, "AlertSound()\n"); - AlertSound( ); - m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); - } - - break; - case TASK_ICHTHYOSAUR_SWIM: - if (m_fSequenceFinished) - { - TaskComplete( ); - } - break; - case TASK_DIE: - if ( m_fSequenceFinished ) - { - pev->deadflag = DEAD_DEAD; - - TaskComplete( ); - } - break; - - case TASK_ICHTHYOSAUR_FLOAT: - pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); - pev->velocity = pev->velocity * 0.8; - if (pev->waterlevel > 1 && pev->velocity.z < 64) - { - pev->velocity.z += 8; - } - else - { - pev->velocity.z -= 8; - } - // ALERT( at_console, "%f\n", pev->velocity.z ); - break; - - default: - CFlyingMonster :: RunTask ( pTask ); - break; - } -} - - - -float CIchthyosaur::VectorToPitch( const Vector &vec ) -{ - float pitch; - if (vec.z == 0 && vec.x == 0) - pitch = 0; - else - { - pitch = (int) (atan2(vec.z, sqrt(vec.x*vec.x+vec.y*vec.y)) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - return pitch; -} - -//========================================================= -void CIchthyosaur::Move(float flInterval) -{ - CFlyingMonster::Move( flInterval ); -} - -float CIchthyosaur::FlPitchDiff( void ) -{ - float flPitchDiff; - float flCurrentPitch; - - flCurrentPitch = UTIL_AngleMod( pev->angles.z ); - - if ( flCurrentPitch == pev->idealpitch ) - { - return 0; - } - - flPitchDiff = pev->idealpitch - flCurrentPitch; - - if ( pev->idealpitch > flCurrentPitch ) - { - if (flPitchDiff >= 180) - flPitchDiff = flPitchDiff - 360; - } - else - { - if (flPitchDiff <= -180) - flPitchDiff = flPitchDiff + 360; - } - return flPitchDiff; -} - -float CIchthyosaur :: ChangePitch( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlPitchDiff(); - float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) - { - if (diff < -20) - target = 45; - else if (diff > 20) - target = -45; - } - pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); - } - return 0; -} - -float CIchthyosaur::ChangeYaw( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if ( m_IdealActivity != GetStoppedActivity() ) - { - if ( diff < -20 ) - target = 20; - else if ( diff > 20 ) - target = -20; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); - } - return CFlyingMonster::ChangeYaw( speed ); -} - - -Activity CIchthyosaur:: GetStoppedActivity( void ) -{ - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - return ACT_WALK; -} - -void CIchthyosaur::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - m_SaveVelocity = vecDir * m_flightSpeed; -} - - -void CIchthyosaur::MonsterThink ( void ) -{ - CFlyingMonster::MonsterThink( ); - - if (pev->deadflag == DEAD_NO) - { - if (m_MonsterState != MONSTERSTATE_SCRIPT) - { - Swim( ); - - // blink the eye - if (m_flBlink < gpGlobals->time) - { - pev->skin = EYE_CLOSED; - if (m_flBlink + 0.2 < gpGlobals->time) - { - m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - if (m_bOnAttack) - pev->skin = EYE_MAD; - else - pev->skin = EYE_BASE; - } - } - } - } -} - -void CIchthyosaur :: Stop( void ) -{ - if (!m_bOnAttack) - m_flightSpeed = 80.0; -} - -void CIchthyosaur::Swim( ) -{ - Vector start = pev->origin; - - Vector Angles; - Vector Forward, Right, Up; - - if (FBitSet( pev->flags, FL_ONGROUND)) - { - pev->angles.x = 0; - pev->angles.y += RANDOM_FLOAT( -45, 45 ); - ClearBits( pev->flags, FL_ONGROUND ); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - - pev->velocity = Forward * 200 + Up * 200; - - return; - } - - if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) - { - m_flightSpeed += 40; - } - if (m_flightSpeed < 180) - { - if (m_IdealActivity == ACT_RUN) - SetActivity( ACT_WALK ); - if (m_IdealActivity == ACT_WALK) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "walk %.2f\n", pev->framerate ); - } - else - { - if (m_IdealActivity == ACT_WALK) - SetActivity( ACT_RUN ); - if (m_IdealActivity == ACT_RUN) - pev->framerate = m_flightSpeed / 150.0; - // ALERT( at_console, "run %.2f\n", pev->framerate ); - } - -/* - if (!m_pBeam) - { - m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); - m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); - m_pBeam->SetEndAttachment( 1 ); - m_pBeam->SetColor( 255, 180, 96 ); - m_pBeam->SetBrightness( 192 ); - } -*/ -#define PROBE_LENGTH 150 - Angles = UTIL_VecToAngles( m_SaveVelocity ); - Angles.x = -Angles.x; - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - - Vector f, u, l, r, d; - f = DoProbe(start + PROBE_LENGTH * Forward); - r = DoProbe(start + PROBE_LENGTH/3 * Forward+Right); - l = DoProbe(start + PROBE_LENGTH/3 * Forward-Right); - u = DoProbe(start + PROBE_LENGTH/3 * Forward+Up); - d = DoProbe(start + PROBE_LENGTH/3 * Forward-Up); - - Vector SteeringVector = f+r+l+u+d; - m_SaveVelocity = (m_SaveVelocity + SteeringVector/2).Normalize(); - - Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); - // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); - - float flDot = DotProduct( Forward, m_SaveVelocity ); - if (flDot > 0.5) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; - else if (flDot > 0) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * (flDot + 0.5); - else - pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; - - // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); - - - // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); - -/* - m_pBeam->SetStartPos( pev->origin + pev->velocity ); - m_pBeam->RelinkBeam( ); -*/ - - // ALERT( at_console, "speed %f\n", m_flightSpeed ); - - Angles = UTIL_VecToAngles( m_SaveVelocity ); - - // Smooth Pitch - // - if (Angles.x > 180) - Angles.x = Angles.x - 360; - pev->angles.x = UTIL_Approach(Angles.x, pev->angles.x, 50 * 0.1 ); - if (pev->angles.x < -80) pev->angles.x = -80; - if (pev->angles.x > 80) pev->angles.x = 80; - - // Smooth Yaw and generate Roll - // - float turn = 360; - // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); - - if (fabs(Angles.y - pev->angles.y) < fabs(turn)) - { - turn = Angles.y - pev->angles.y; - } - if (fabs(Angles.y - pev->angles.y + 360) < fabs(turn)) - { - turn = Angles.y - pev->angles.y + 360; - } - if (fabs(Angles.y - pev->angles.y - 360) < fabs(turn)) - { - turn = Angles.y - pev->angles.y - 360; - } - - float speed = m_flightSpeed * 0.1; - - // ALERT( at_console, "speed %.0f %f\n", turn, speed ); - if (fabs(turn) > speed) - { - if (turn < 0.0) - { - turn = -speed; - } - else - { - turn = speed; - } - } - pev->angles.y += turn; - pev->angles.z -= turn; - pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); - - static float yaw_adj; - - yaw_adj = yaw_adj * 0.8 + turn; - - // ALERT( at_console, "yaw %f : %f\n", turn, yaw_adj ); - - SetBoneController( 0, -yaw_adj / 4.0 ); - - // Roll Smoothing - // - turn = 360; - if (fabs(Angles.z - pev->angles.z) < fabs(turn)) - { - turn = Angles.z - pev->angles.z; - } - if (fabs(Angles.z - pev->angles.z + 360) < fabs(turn)) - { - turn = Angles.z - pev->angles.z + 360; - } - if (fabs(Angles.z - pev->angles.z - 360) < fabs(turn)) - { - turn = Angles.z - pev->angles.z - 360; - } - speed = m_flightSpeed/2 * 0.1; - if (fabs(turn) < speed) - { - pev->angles.z += turn; - } - else - { - if (turn < 0.0) - { - pev->angles.z -= speed; - } - else - { - pev->angles.z += speed; - } - } - if (pev->angles.z < -20) pev->angles.z = -20; - if (pev->angles.z > 20) pev->angles.z = 20; - - UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up); - - // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); -} - - -Vector CIchthyosaur::DoProbe(const Vector &Probe) -{ - Vector WallNormal = Vector(0,0,-1); // WATER normal is Straight Down for fish. - float frac; - BOOL bBumpedSomething = ProbeZ(pev->origin, Probe, &frac); - - TraceResult tr; - TRACE_MONSTER_HULL(edict(), pev->origin, Probe, dont_ignore_monsters, edict(), &tr); - if ( tr.fAllSolid || tr.flFraction < 0.99 ) - { - if (tr.flFraction < 0.0) tr.flFraction = 0.0; - if (tr.flFraction > 1.0) tr.flFraction = 1.0; - if (tr.flFraction < frac) - { - frac = tr.flFraction; - bBumpedSomething = TRUE; - WallNormal = tr.vecPlaneNormal; - } - } - - if (bBumpedSomething && (m_hEnemy == 0 || tr.pHit != m_hEnemy->edict())) - { - Vector ProbeDir = Probe - pev->origin; - - Vector NormalToProbeAndWallNormal = CrossProduct(ProbeDir, WallNormal); - Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir); - - float SteeringForce = m_flightSpeed * (1-frac) * (DotProduct(WallNormal.Normalize(), m_SaveVelocity.Normalize())); - if (SteeringForce < 0.0) - { - SteeringForce = -SteeringForce; - } - SteeringVector = SteeringForce * SteeringVector.Normalize(); - - return SteeringVector; - } - return Vector(0, 0, 0); -} - -#endif diff --git a/sdk/dlls/islave.cpp b/sdk/dlls/islave.cpp deleted file mode 100644 index aad96f8..0000000 --- a/sdk/dlls/islave.cpp +++ /dev/null @@ -1,864 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Alien slave monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "squadmonster.h" -#include "schedule.h" -#include "effects.h" -#include "weapons.h" -#include "soundent.h" - -extern DLL_GLOBAL int g_iSkillLevel; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ISLAVE_AE_CLAW ( 1 ) -#define ISLAVE_AE_CLAWRAKE ( 2 ) -#define ISLAVE_AE_ZAP_POWERUP ( 3 ) -#define ISLAVE_AE_ZAP_SHOOT ( 4 ) -#define ISLAVE_AE_ZAP_DONE ( 5 ) - -#define ISLAVE_MAX_BEAMS 8 - -class CISlave : public CSquadMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - int Classify ( void ); - int IRelationship( CBaseEntity *pTarget ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - BOOL CheckRangeAttack1 ( float flDot, float flDist ); - BOOL CheckRangeAttack2 ( float flDot, float flDist ); - void CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - - void DeathSound( void ); - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - void StartTask ( Task_t *pTask ); - Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - CUSTOM_SCHEDULES; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void ClearBeams( ); - void ArmBeam( int side ); - void WackBeam( int side, CBaseEntity *pEntity ); - void ZapBeam( int side ); - void BeamGlow( void ); - - int m_iBravery; - - CBeam *m_pBeam[ISLAVE_MAX_BEAMS]; - - int m_iBeams; - float m_flNextAttack; - - int m_voicePitch; - - EHANDLE m_hDead; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - static const char *pPainSounds[]; - static const char *pDeathSounds[]; -}; -LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave ); -LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave ); - - -TYPEDESCRIPTION CISlave::m_SaveData[] = -{ - DEFINE_FIELD( CISlave, m_iBravery, FIELD_INTEGER ), - - DEFINE_ARRAY( CISlave, m_pBeam, FIELD_CLASSPTR, ISLAVE_MAX_BEAMS ), - DEFINE_FIELD( CISlave, m_iBeams, FIELD_INTEGER ), - DEFINE_FIELD( CISlave, m_flNextAttack, FIELD_TIME ), - - DEFINE_FIELD( CISlave, m_voicePitch, FIELD_INTEGER ), - - DEFINE_FIELD( CISlave, m_hDead, FIELD_EHANDLE ), - -}; - -IMPLEMENT_SAVERESTORE( CISlave, CSquadMonster ); - - - - -const char *CISlave::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CISlave::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CISlave::pPainSounds[] = -{ - "aslave/slv_pain1.wav", - "aslave/slv_pain2.wav", -}; - -const char *CISlave::pDeathSounds[] = -{ - "aslave/slv_die1.wav", - "aslave/slv_die2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CISlave :: Classify ( void ) -{ - return CLASS_ALIEN_MILITARY; -} - - -int CISlave::IRelationship( CBaseEntity *pTarget ) -{ - if ( (pTarget->IsPlayer()) ) - if ( (pev->spawnflags & SF_MONSTER_WAIT_UNTIL_PROVOKED ) && ! (m_afMemory & bits_MEMORY_PROVOKED )) - return R_NO; - return CBaseMonster::IRelationship( pTarget ); -} - - -void CISlave :: CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation ) -{ - // ALERT( at_aiconsole, "help " ); - - // skip ones not on my netname - if ( FStringNull( pev->netname )) - return; - - CBaseEntity *pEntity = NULL; - - while ((pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ))) != NULL) - { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer( ); - if (pMonster) - { - pMonster->m_afMemory |= bits_MEMORY_PROVOKED; - pMonster->PushEnemy( hEnemy, vecLocation ); - } - } - } -} - - -//========================================================= -// ALertSound - scream -//========================================================= -void CISlave :: AlertSound( void ) -{ - if ( m_hEnemy != 0 ) - { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch); - - CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP ); - } -} - -//========================================================= -// IdleSound -//========================================================= -void CISlave :: IdleSound( void ) -{ - if (RANDOM_LONG( 0, 2 ) == 0) - { - SENTENCEG_PlayRndSz(ENT(pev), "SLV_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch); - } - -#if 0 - int side = RANDOM_LONG( 0, 1 ) * 2 - 1; - - ClearBeams( ); - ArmBeam( side ); - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecSrc.x); // X - WRITE_COORD(vecSrc.y); // Y - WRITE_COORD(vecSrc.z); // Z - WRITE_BYTE( 8 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 10 ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 ); -#endif -} - -//========================================================= -// PainSound -//========================================================= -void CISlave :: PainSound( void ) -{ - if (RANDOM_LONG( 0, 2 ) == 0) - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } -} - -//========================================================= -// DieSound -//========================================================= - -void CISlave :: DeathSound( void ) -{ - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pDeathSounds[ RANDOM_LONG(0,ARRAYSIZE(pDeathSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); -} - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. -//========================================================= -int CISlave :: ISoundMask ( void) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - - -void CISlave::Killed( entvars_t *pevAttacker, int iGib ) -{ - ClearBeams( ); - CSquadMonster::Killed( pevAttacker, iGib ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CISlave :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_WALK: - ys = 50; - break; - case ACT_RUN: - ys = 70; - break; - case ACT_IDLE: - ys = 50; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -// -// Returns number of events handled, 0 if none. -//========================================================= -void CISlave :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - // ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame ); - switch( pEvent->event ) - { - case ISLAVE_AE_CLAW: - { - // SOUND HERE! - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClaw, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - // Play a random attack hit sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - - case ISLAVE_AE_CLAWRAKE: - { - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.slaveDmgClawrake, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - else - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch ); - } - } - break; - - case ISLAVE_AE_ZAP_POWERUP: - { - // speed up attack when on hard - if (g_iSkillLevel == SKILL_HARD) - pev->framerate = 1.5; - - UTIL_MakeAimVectors( pev->angles ); - - if (m_iBeams == 0) - { - Vector vecSrc = pev->origin + gpGlobals->v_forward * 2; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE(TE_DLIGHT); - WRITE_COORD(vecSrc.x); // X - WRITE_COORD(vecSrc.y); // Y - WRITE_COORD(vecSrc.z); // Z - WRITE_BYTE( 12 ); // radius * 0.1 - WRITE_BYTE( 255 ); // r - WRITE_BYTE( 180 ); // g - WRITE_BYTE( 96 ); // b - WRITE_BYTE( 20 / pev->framerate ); // time * 10 - WRITE_BYTE( 0 ); // decay * 0.1 - MESSAGE_END( ); - - } - if (m_hDead != 0) - { - WackBeam( -1, m_hDead ); - WackBeam( 1, m_hDead ); - } - else - { - ArmBeam( -1 ); - ArmBeam( 1 ); - BeamGlow( ); - } - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 ); - pev->skin = m_iBeams / 2; - } - break; - - case ISLAVE_AE_ZAP_SHOOT: - { - ClearBeams( ); - - if (m_hDead != 0) - { - Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 ); - TraceResult trace; - UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace ); - - if ( !trace.fStartSolid ) - { - CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles ); - pNew->pev->spawnflags |= 1; - WackBeam( -1, pNew ); - WackBeam( 1, pNew ); - UTIL_Remove( m_hDead ); - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - - /* - CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles ); - pEffect->Use( this, this, USE_ON, 1 ); - */ - break; - } - } - ClearMultiDamage(); - - UTIL_MakeAimVectors( pev->angles ); - - ZapBeam( -1 ); - ZapBeam( 1 ); - - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "hassault/hw_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) ); - // STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); - ApplyMultiDamage(pev, pev); - - m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 ); - } - break; - - case ISLAVE_AE_ZAP_DONE: - { - ClearBeams( ); - } - break; - - default: - CSquadMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// CheckRangeAttack1 - normal beam attack -//========================================================= -BOOL CISlave :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if (m_flNextAttack > gpGlobals->time) - { - return FALSE; - } - - return CSquadMonster::CheckRangeAttack1( flDot, flDist ); -} - -//========================================================= -// CheckRangeAttack2 - check bravery and try to resurect dead comrades -//========================================================= -BOOL CISlave :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - return FALSE; - - if (m_flNextAttack > gpGlobals->time) - { - return FALSE; - } - - m_hDead = NULL; - m_iBravery = 0; - - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" )) != NULL) - { - TraceResult tr; - - UTIL_TraceLine( EyePosition( ), pEntity->EyePosition( ), ignore_monsters, ENT(pev), &tr ); - if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict()) - { - if (pEntity->pev->deadflag == DEAD_DEAD) - { - float d = (pev->origin - pEntity->pev->origin).Length(); - if (d < flDist) - { - m_hDead = pEntity; - flDist = d; - } - m_iBravery--; - } - else - { - m_iBravery++; - } - } - } - if (m_hDead != 0) - return TRUE; - else - return FALSE; -} - - -//========================================================= -// StartTask -//========================================================= -void CISlave :: StartTask ( Task_t *pTask ) -{ - ClearBeams( ); - - CSquadMonster :: StartTask ( pTask ); -} - - -//========================================================= -// Spawn -//========================================================= -void CISlave :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/islave.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.slaveHealth; - pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP; - - m_voicePitch = RANDOM_LONG( 85, 110 ); - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CISlave :: Precache() -{ - size_t i; - - PRECACHE_MODEL("models/islave.mdl"); - PRECACHE_MODEL("sprites/lgtning.spr"); - PRECACHE_SOUND("debris/zap1.wav"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("hassault/hw_shoot1.wav"); - PRECACHE_SOUND("zombie/zo_pain2.wav"); - PRECACHE_SOUND("headcrab/hc_headbite.wav"); - PRECACHE_SOUND("weapons/cbar_miss1.wav"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ ) - PRECACHE_SOUND((char *)pDeathSounds[i]); - - UTIL_PrecacheOther( "test_effect" ); -} - - -//========================================================= -// TakeDamage - get provoked when injured -//========================================================= - -int CISlave :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - // don't slash one of your own - if ((bitsDamageType & DMG_SLASH) && pevAttacker && IRelationship( Instance(pevAttacker) ) < R_DL) - return 0; - - m_afMemory |= bits_MEMORY_PROVOKED; - return CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -void CISlave::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if (bitsDamageType & DMG_SHOCK) - return; - - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - - -// primary range attack -Task_t tlSlaveAttack1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSlaveAttack1[] = -{ - { - tlSlaveAttack1, - ARRAYSIZE ( tlSlaveAttack1 ), - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_HEAR_SOUND | - bits_COND_HEAVY_DAMAGE, - - bits_SOUND_DANGER, - "Slave Range Attack1" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CISlave ) -{ - slSlaveAttack1, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CISlave, CSquadMonster ); - - -//========================================================= -//========================================================= -Schedule_t *CISlave :: GetSchedule( void ) -{ - ClearBeams( ); - -/* - if (pev->spawnflags) - { - pev->spawnflags = 0; - return GetScheduleOfType( SCHED_RELOAD ); - } -*/ - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - if ( pSound->m_iType & bits_SOUND_COMBAT ) - m_afMemory |= bits_MEMORY_PROVOKED; - } - - switch (m_MonsterState) - { - case MONSTERSTATE_COMBAT: -// dead enemy - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // call base class, all code to handle dead enemies is centralized there. - return CBaseMonster :: GetSchedule(); - } - - if (pev->health < 20 || m_iBravery < 0) - { - if (!HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) - { - m_failSchedule = SCHED_CHASE_ENEMY; - if (HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - // ALERT( at_console, "exposed\n"); - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } - } - break; - default: - break; - } - return CSquadMonster::GetSchedule( ); -} - - -Schedule_t *CISlave :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_FAIL: - if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 )) - { - return CSquadMonster :: GetScheduleOfType( SCHED_MELEE_ATTACK1 ); ; - } - break; - case SCHED_RANGE_ATTACK1: - return slSlaveAttack1; - case SCHED_RANGE_ATTACK2: - return slSlaveAttack1; - } - return CSquadMonster :: GetScheduleOfType( Type ); -} - - -//========================================================= -// ArmBeam - small beam from arm to nearby geometry -//========================================================= - -void CISlave :: ArmBeam( int side ) -{ - TraceResult tr; - float flDist = 1.0; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - UTIL_MakeAimVectors( pev->angles ); - Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32; - - for (int i = 0; i < 3; i++) - { - Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 ); - TraceResult tr1; - UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1); - if (flDist > tr1.flFraction) - { - tr = tr1; - flDist = tr.flFraction; - } - } - - // Couldn't find anything close enough - if ( flDist == 1.0 ) - return; - - DecalGunshot( &tr, BULLET_PLAYER_CROWBAR ); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - // m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); - m_pBeam[m_iBeams]->SetBrightness( 64 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - - -//========================================================= -// BeamGlow - brighten all beams -//========================================================= -void CISlave :: BeamGlow( ) -{ - int b = m_iBeams * 32; - if (b > 255) - b = 255; - - for (int i = 0; i < m_iBeams; i++) - { - if (m_pBeam[i]->GetBrightness() != 255) - { - m_pBeam[i]->SetBrightness( b ); - } - } -} - - -//========================================================= -// WackBeam - regenerate dead colleagues -//========================================================= -void CISlave :: WackBeam( int side, CBaseEntity *pEntity ) -{ - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - if (pEntity == NULL) - return; - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 80 ); - m_iBeams++; -} - -//========================================================= -// ZapBeam - heavy damage directly forward -//========================================================= -void CISlave :: ZapBeam( int side ) -{ - Vector vecSrc, vecAim; - TraceResult tr; - CBaseEntity *pEntity; - - if (m_iBeams >= ISLAVE_MAX_BEAMS) - return; - - vecSrc = pev->origin + gpGlobals->v_up * 36; - vecAim = ShootAtEnemy( vecSrc ); - float deflection = 0.01; - vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection ); - UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr); - - m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 ); - if (!m_pBeam[m_iBeams]) - return; - - m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) ); - m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); - m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); - m_pBeam[m_iBeams]->SetBrightness( 255 ); - m_pBeam[m_iBeams]->SetNoise( 20 ); - m_iBeams++; - - pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - pEntity->TraceAttack( pev, gSkillData.slaveDmgZap, vecAim, &tr, DMG_SHOCK ); - } - UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); -} - - -//========================================================= -// ClearBeams - remove all beams -//========================================================= -void CISlave :: ClearBeams( ) -{ - for (int i = 0; i < ISLAVE_MAX_BEAMS; i++) - { - if (m_pBeam[i]) - { - UTIL_Remove( m_pBeam[i] ); - m_pBeam[i] = NULL; - } - } - m_iBeams = 0; - pev->skin = 0; - - STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" ); -} diff --git a/sdk/dlls/items.cpp b/sdk/dlls/items.cpp deleted file mode 100644 index 5a4a7e0..0000000 --- a/sdk/dlls/items.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== items.cpp ======================================================== - - functions governing the selection/use of weapons for players - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "skill.h" -#include "items.h" -#include "gamerules.h" - -extern int gmsgItemPickup; - -class CWorldItem : public CBaseEntity -{ -public: - void KeyValue(KeyValueData *pkvd ); - void Spawn( void ); - int m_iType; -}; - -LINK_ENTITY_TO_CLASS(world_items, CWorldItem); - -void CWorldItem::KeyValue(KeyValueData *pkvd) -{ - if (FStrEq(pkvd->szKeyName, "type")) - { - m_iType = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CWorldItem::Spawn( void ) -{ - CBaseEntity *pEntity = NULL; - - switch (m_iType) - { - case 44: // ITEM_BATTERY: - pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); - break; - case 42: // ITEM_ANTIDOTE: - pEntity = CBaseEntity::Create( "item_antidote", pev->origin, pev->angles ); - break; - case 43: // ITEM_SECURITY: - pEntity = CBaseEntity::Create( "item_security", pev->origin, pev->angles ); - break; - case 45: // ITEM_SUIT: - pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); - break; - } - - if (!pEntity) - { - ALERT( at_console, "unable to create world_item %d\n", m_iType ); - } - else - { - pEntity->pev->target = pev->target; - pEntity->pev->targetname = pev->targetname; - pEntity->pev->spawnflags = pev->spawnflags; - } - - REMOVE_ENTITY(edict()); -} - - -void CItem::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - SetTouch(&CItem::ItemTouch); - - if (DROP_TO_FLOOR(ENT(pev)) == 0) - { - ALERT(at_error, "Item %s fell out of level at %f,%f,%f", STRING( pev->classname ), pev->origin.x, pev->origin.y, pev->origin.z); - UTIL_Remove( this ); - return; - } -} - -extern int gEvilImpulse101; - -void CItem::ItemTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - { - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // ok, a player is touching this item, but can he have it? - if ( !g_pGameRules->CanHaveItem( pPlayer, this ) ) - { - // no? Ignore the touch. - return; - } - - if (MyTouch( pPlayer )) - { - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - SetTouch( NULL ); - - // player grabbed the item. - g_pGameRules->PlayerGotItem( pPlayer, this ); - if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) - { - Respawn(); - } - else - { - UTIL_Remove( this ); - } - } - else if (gEvilImpulse101) - { - UTIL_Remove( this ); - } -} - -CBaseEntity* CItem::Respawn( void ) -{ - SetTouch( NULL ); - pev->effects |= EF_NODRAW; - - UTIL_SetOrigin( pev, g_pGameRules->VecItemRespawnSpot( this ) );// blip to whereever you should respawn. - - SetThink ( &CItem::Materialize ); - pev->nextthink = g_pGameRules->FlItemRespawnTime( this ); - return this; -} - -void CItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch( &CItem::ItemTouch ); -} - -#define SF_SUIT_SHORTLOGON 0x0001 - -class CItemSuit : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_suit.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_suit.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->pev->weapons & (1<spawnflags & SF_SUIT_SHORTLOGON ) - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_A0"); // short version of suit logon, - else - EMIT_SOUND_SUIT(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon - - pPlayer->pev->weapons |= (1<pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue += gSkillData.batteryCapacity; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY); - - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - - - // Suit reports new power level - // For some reason this wasn't working in release build -- round it. - pct = (int)( (float)(pPlayer->pev->armorvalue * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5); - pct = (pct / 5); - if (pct > 0) - pct--; - - sprintf( szcharge,"!HEV_%1dP", pct ); - - //EMIT_SOUND_SUIT(ENT(pev), szcharge); - pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC); - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); - - -class CItemAntidote : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_antidote.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_antidote.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->SetSuitUpdate("!HEV_DET4", FALSE, SUIT_NEXT_IN_1MIN); - - pPlayer->m_rgItems[ITEM_ANTIDOTE] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_antidote, CItemAntidote); - - -class CItemSecurity : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_security.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_security.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - pPlayer->m_rgItems[ITEM_SECURITY] += 1; - return TRUE; - } -}; - -LINK_ENTITY_TO_CLASS(item_security, CItemSecurity); - -class CItemLongJump : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_longjump.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_longjump.mdl"); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ( pPlayer->m_fLongJump ) - { - return FALSE; - } - - if ( ( pPlayer->pev->weapons & (1<m_fLongJump = TRUE;// player now has longjump module - - g_engfuncs.pfnSetPhysicsKeyValue( pPlayer->edict(), "slj", "1" ); - - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - - EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound? - return TRUE; - } - return FALSE; - } -}; - -LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); diff --git a/sdk/dlls/items.h b/sdk/dlls/items.h deleted file mode 100644 index e985296..0000000 --- a/sdk/dlls/items.h +++ /dev/null @@ -1,29 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef ITEMS_H -#define ITEMS_H - - -class CItem : public CBaseEntity -{ -public: - void Spawn( void ); - CBaseEntity* Respawn( void ); - void EXPORT ItemTouch( CBaseEntity *pOther ); - void EXPORT Materialize( void ); - virtual BOOL MyTouch( CBasePlayer *pPlayer ) { return FALSE; }; -}; - -#endif // ITEMS_H diff --git a/sdk/dlls/leech.cpp b/sdk/dlls/leech.cpp deleted file mode 100644 index 863359e..0000000 --- a/sdk/dlls/leech.cpp +++ /dev/null @@ -1,723 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// leech - basic little swimming monster -//========================================================= -// -// UNDONE: -// DONE:Steering force model for attack -// DONE:Attack animation control / damage -// DONE:Establish range of up/down motion and steer around vertical obstacles -// DONE:Re-evaluate height periodically -// DONE:Fall (MOVETYPE_TOSS) and play different anim if out of water -// Test in complex room (c2a3?) -// DONE:Sounds? - Kelly will fix -// Blood cloud? Hurt effect? -// Group behavior? -// DONE:Save/restore -// Flop animation - just bind to ACT_TWITCH -// Fix fatal push into wall case -// -// Try this on a bird -// Try this on a model with hulls/tracehull? -// - - -#include "float.h" -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - - - - -// Animation events -#define LEECH_AE_ATTACK 1 -#define LEECH_AE_FLOP 2 - - -// Movement constants - -#define LEECH_ACCELERATE 10 -#define LEECH_CHECK_DIST 45 -#define LEECH_SWIM_SPEED 50 -#define LEECH_SWIM_ACCEL 80 -#define LEECH_SWIM_DECEL 10 -#define LEECH_TURN_RATE 90 -#define LEECH_SIZEX 10 -#define LEECH_FRAMETIME 0.1 - - - -#define DEBUG_BEAMS 0 - -#if DEBUG_BEAMS -#include "effects.h" -#endif - - -class CLeech : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SwimThink( void ); - void EXPORT DeadThink( void ); - void Touch( CBaseEntity *pOther ) - { - if ( pOther->IsPlayer() ) - { - // If the client is pushing me, give me some base velocity - if ( gpGlobals->trace_ent && gpGlobals->trace_ent == edict() ) - { - pev->basevelocity = pOther->pev->velocity; - pev->flags |= FL_BASEVELOCITY; - } - } - } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector(-8,-8,0); - pev->absmax = pev->origin + Vector(8,8,2); - } - - void AttackSound( void ); - void AlertSound( void ); - void UpdateMotion( void ); - float ObstacleDistance( CBaseEntity *pTarget ); - void MakeVectors( void ); - void RecalculateWaterlevel( void ); - void SwitchLeechState( void ); - - // Base entity functions - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - void Activate( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - int Classify( void ) { return CLASS_INSECT; } - int IRelationship( CBaseEntity *pTarget ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackSounds[]; - static const char *pAlertSounds[]; - -private: - // UNDONE: Remove unused boid vars, do group behavior - float m_flTurning;// is this boid turning? - BOOL m_fPathBlocked;// TRUE if there is an obstacle ahead - float m_flAccelerate; - float m_obstacle; - float m_top; - float m_bottom; - float m_height; - float m_waterTime; - float m_sideTime; // Timer to randomly check clearance on sides - float m_zTime; - float m_stateTime; - float m_attackSoundTime; - -#if DEBUG_BEAMS - CBeam *m_pb; - CBeam *m_pt; -#endif -}; - - - -LINK_ENTITY_TO_CLASS( monster_leech, CLeech ); - -TYPEDESCRIPTION CLeech::m_SaveData[] = -{ - DEFINE_FIELD( CLeech, m_flTurning, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_fPathBlocked, FIELD_BOOLEAN ), - DEFINE_FIELD( CLeech, m_flAccelerate, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_obstacle, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_top, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_bottom, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CLeech, m_waterTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_sideTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_zTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_stateTime, FIELD_TIME ), - DEFINE_FIELD( CLeech, m_attackSoundTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CLeech, CBaseMonster ); - - -const char *CLeech::pAttackSounds[] = -{ - "leech/leech_bite1.wav", - "leech/leech_bite2.wav", - "leech/leech_bite3.wav", -}; - -const char *CLeech::pAlertSounds[] = -{ - "leech/leech_alert1.wav", - "leech/leech_alert2.wav", -}; - - -void CLeech::Spawn( void ) -{ - Precache(); - SET_MODEL(ENT(pev), "models/leech.mdl"); - // Just for fun - // SET_MODEL(ENT(pev), "models/icky.mdl"); - -// UTIL_SetSize( pev, g_vecZero, g_vecZero ); - UTIL_SetSize( pev, Vector(-1,-1,0), Vector(1,1,2)); - // Don't push the minz down too much or the water check will fail because this entity is really point-sized - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_FLY; - SetBits(pev->flags, FL_SWIM); - pev->health = gSkillData.leechHealth; - - m_flFieldOfView = -0.5; // 180 degree FOV - m_flDistLook = 750; - MonsterInit(); - SetThink( &CLeech::SwimThink ); - SetUse( NULL ); - SetTouch( NULL ); - pev->view_ofs = g_vecZero; - - m_flTurning = 0; - m_fPathBlocked = FALSE; - SetActivity( ACT_SWIM ); - SetState( MONSTERSTATE_IDLE ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 1, 5 ); -} - - -void CLeech::Activate( void ) -{ - RecalculateWaterlevel(); -} - - - -void CLeech::RecalculateWaterlevel( void ) -{ - // Calculate boundaries - Vector vecTest = pev->origin - Vector(0,0,400); - - TraceResult tr; - - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if ( tr.flFraction != 1.0 ) - m_bottom = tr.vecEndPos.z + 1; - else - m_bottom = vecTest.z; - - m_top = UTIL_WaterLevel( pev->origin, pev->origin.z, pev->origin.z + 400 ) - 1; - - // Chop off 20% of the outside range - float newBottom = m_bottom * 0.8 + m_top * 0.2; - m_top = m_bottom * 0.2 + m_top * 0.8; - m_bottom = newBottom; - m_height = RANDOM_FLOAT( m_bottom, m_top ); - m_waterTime = gpGlobals->time + RANDOM_FLOAT( 5, 7 ); -} - - -void CLeech::SwitchLeechState( void ) -{ - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 3, 6 ); - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - m_hEnemy = NULL; - SetState( MONSTERSTATE_IDLE ); - // We may be up against the player, so redo the side checks - m_sideTime = 0; - } - else - { - Look( m_flDistLook ); - CBaseEntity *pEnemy = BestVisibleEnemy(); - if ( pEnemy && pEnemy->pev->waterlevel != 0 ) - { - m_hEnemy = pEnemy; - SetState( MONSTERSTATE_COMBAT ); - m_stateTime = gpGlobals->time + RANDOM_FLOAT( 18, 25 ); - AlertSound(); - } - } -} - - -int CLeech::IRelationship( CBaseEntity *pTarget ) -{ - if ( pTarget->IsPlayer() ) - return R_DL; - return CBaseMonster::IRelationship( pTarget ); -} - - - -void CLeech::AttackSound( void ) -{ - if ( gpGlobals->time > m_attackSoundTime ) - { - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM ); - m_attackSoundTime = gpGlobals->time + 0.5; - } -} - - -void CLeech::AlertSound( void ) -{ - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM * 0.5, 0, PITCH_NORM ); -} - - -void CLeech::Precache( void ) -{ - size_t i; - - //PRECACHE_MODEL("models/icky.mdl"); - PRECACHE_MODEL("models/leech.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); -} - - -int CLeech::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - pev->velocity = g_vecZero; - - // Nudge the leech away from the damage - if ( pevInflictor ) - { - pev->velocity = (pev->origin - pevInflictor->origin).Normalize() * 25; - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - - -void CLeech::HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case LEECH_AE_ATTACK: - AttackSound(); - CBaseEntity *pEnemy; - - pEnemy = m_hEnemy; - if ( pEnemy != NULL ) - { - Vector dir, face; - - UTIL_MakeVectorsPrivate( pev->angles, face, NULL, NULL ); - face.z = 0; - dir = (pEnemy->pev->origin - pev->origin); - dir.z = 0; - dir = dir.Normalize(); - face = face.Normalize(); - - - if ( DotProduct(dir, face) > 0.9 ) // Only take damage if the leech is facing the prey - pEnemy->TakeDamage( pev, pev, gSkillData.leechDmgBite, DMG_SLASH ); - } - m_stateTime -= 2; - break; - - case LEECH_AE_FLOP: - // Play flop sound - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - - -void CLeech::MakeVectors( void ) -{ - Vector tmp = pev->angles; - tmp.x = -tmp.x; - UTIL_MakeVectors ( tmp ); -} - - -// -// ObstacleDistance - returns normalized distance to obstacle -// -float CLeech::ObstacleDistance( CBaseEntity *pTarget ) -{ - TraceResult tr; - Vector vecTest; - - // use VELOCITY, not angles, not all boids point the direction they are flying - //Vector vecDir = UTIL_VecToAngles( pev->velocity ); - MakeVectors(); - - // check for obstacle ahead - vecTest = pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - - if ( tr.fStartSolid ) - { - pev->speed = -LEECH_SWIM_SPEED * 0.5; -// ALERT( at_console, "Stuck from (%f %f %f) to (%f %f %f)\n", pev->oldorigin.x, pev->oldorigin.y, pev->oldorigin.z, pev->origin.x, pev->origin.y, pev->origin.z ); -// UTIL_SetOrigin( pev, pev->oldorigin ); - } - - if ( tr.flFraction != 1.0 ) - { - if ( (pTarget == NULL || tr.pHit != pTarget->edict()) ) - { - return tr.flFraction; - } - else - { - if ( fabs(m_height - pev->origin.z) > 10 ) - return tr.flFraction; - } - } - - if ( m_sideTime < gpGlobals->time ) - { - // extra wide checks - vecTest = pev->origin + gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if (tr.flFraction != 1.0) - return tr.flFraction; - - vecTest = pev->origin - gpGlobals->v_right * LEECH_SIZEX * 2 + gpGlobals->v_forward * LEECH_CHECK_DIST; - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - if (tr.flFraction != 1.0) - return tr.flFraction; - - // Didn't hit either side, so stop testing for another 0.5 - 1 seconds - m_sideTime = gpGlobals->time + RANDOM_FLOAT(0.5,1); - } - return 1.0; -} - - -void CLeech::DeadThink( void ) -{ - if ( m_fSequenceFinished ) - { - if ( m_Activity == ACT_DIEFORWARD ) - { - SetThink( NULL ); - StopAnimation(); - return; - } - else if ( pev->flags & FL_ONGROUND ) - { - pev->solid = SOLID_NOT; - SetActivity(ACT_DIEFORWARD); - } - } - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - // Apply damage velocity, but keep out of the walls - if ( pev->velocity.x != 0 || pev->velocity.y != 0 ) - { - TraceResult tr; - - // Look 0.5 seconds ahead - UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 0.5, missile, edict(), &tr); - if (tr.flFraction != 1.0) - { - pev->velocity.x = 0; - pev->velocity.y = 0; - } - } -} - - - -void CLeech::UpdateMotion( void ) -{ - float flapspeed = (pev->speed - m_flAccelerate) / LEECH_ACCELERATE; - m_flAccelerate = m_flAccelerate * 0.8 + pev->speed * 0.2; - - if (flapspeed < 0) - flapspeed = -flapspeed; - flapspeed += 1.0; - if (flapspeed < 0.5) - flapspeed = 0.5; - if (flapspeed > 1.9) - flapspeed = 1.9; - - pev->framerate = flapspeed; - - if ( !m_fPathBlocked ) - pev->avelocity.y = pev->ideal_yaw; - else - pev->avelocity.y = pev->ideal_yaw * m_obstacle; - - if ( pev->avelocity.y > 150 ) - m_IdealActivity = ACT_TURN_LEFT; - else if ( pev->avelocity.y < -150 ) - m_IdealActivity = ACT_TURN_RIGHT; - else - m_IdealActivity = ACT_SWIM; - - // lean - float targetPitch, delta; - delta = m_height - pev->origin.z; - - if ( delta < -10 ) - targetPitch = -30; - else if ( delta > 10 ) - targetPitch = 30; - else - targetPitch = 0; - - pev->angles.x = UTIL_Approach( targetPitch, pev->angles.x, 60 * LEECH_FRAMETIME ); - - // bank - pev->avelocity.z = - (pev->angles.z + (pev->avelocity.y * 0.25)); - - if ( m_MonsterState == MONSTERSTATE_COMBAT && HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) - m_IdealActivity = ACT_MELEE_ATTACK1; - - // Out of water check - if ( !pev->waterlevel ) - { - pev->movetype = MOVETYPE_TOSS; - m_IdealActivity = ACT_TWITCH; - pev->velocity = g_vecZero; - - // Animation will intersect the floor if either of these is non-zero - pev->angles.z = 0; - pev->angles.x = 0; - - if ( pev->framerate < 1.0 ) - pev->framerate = 1.0; - } - else if ( pev->movetype == MOVETYPE_TOSS ) - { - pev->movetype = MOVETYPE_FLY; - pev->flags &= ~FL_ONGROUND; - RecalculateWaterlevel(); - m_waterTime = gpGlobals->time + 2; // Recalc again soon, water may be rising - } - - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - float flInterval = StudioFrameAdvance(); - DispatchAnimEvents ( flInterval ); - -#if DEBUG_BEAMS - if ( !m_pb ) - m_pb = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - if ( !m_pt ) - m_pt = CBeam::BeamCreate( "sprites/laserbeam.spr", 5 ); - m_pb->PointsInit( pev->origin, pev->origin + gpGlobals->v_forward * LEECH_CHECK_DIST ); - m_pt->PointsInit( pev->origin, pev->origin - gpGlobals->v_right * (pev->avelocity.y*0.25) ); - if ( m_fPathBlocked ) - { - float color = m_obstacle * 30; - if ( m_obstacle == 1.0 ) - color = 0; - if ( color > 255 ) - color = 255; - m_pb->SetColor( 255, (int)color, (int)color ); - } - else - m_pb->SetColor( 255, 255, 0 ); - m_pt->SetColor( 0, 0, 255 ); -#endif -} - - -void CLeech::SwimThink( void ) -{ - TraceResult tr; - float flLeftSide; - float flRightSide; - float targetSpeed; - float targetYaw = 0; - CBaseEntity *pTarget; - - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); - pev->velocity = g_vecZero; - return; - } - else - pev->nextthink = gpGlobals->time + 0.1; - - targetSpeed = LEECH_SWIM_SPEED; - - if ( m_waterTime < gpGlobals->time ) - RecalculateWaterlevel(); - - if ( m_stateTime < gpGlobals->time ) - SwitchLeechState(); - - ClearConditions( bits_COND_CAN_MELEE_ATTACK1 ); - switch( m_MonsterState ) - { - case MONSTERSTATE_COMBAT: - pTarget = m_hEnemy; - if ( !pTarget ) - SwitchLeechState(); - else - { - // Chase the enemy's eyes - m_height = pTarget->pev->origin.z + pTarget->pev->view_ofs.z - 5; - // Clip to viable water area - if ( m_height < m_bottom ) - m_height = m_bottom; - else if ( m_height > m_top ) - m_height = m_top; - Vector location = pTarget->pev->origin - pev->origin; - location.z += (pTarget->pev->view_ofs.z); - if ( location.Length() < 40 ) - SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); - // Turn towards target ent - targetYaw = UTIL_VecToYaw( location ); - - targetYaw = UTIL_AngleDiff( targetYaw, UTIL_AngleMod( pev->angles.y ) ); - - if ( targetYaw < (-LEECH_TURN_RATE*0.75) ) - targetYaw = (-LEECH_TURN_RATE*0.75); - else if ( targetYaw > (LEECH_TURN_RATE*0.75) ) - targetYaw = (LEECH_TURN_RATE*0.75); - else - targetSpeed *= 2; - } - - break; - - default: - if ( m_zTime < gpGlobals->time ) - { - float newHeight = RANDOM_FLOAT( m_bottom, m_top ); - m_height = 0.5 * m_height + 0.5 * newHeight; - m_zTime = gpGlobals->time + RANDOM_FLOAT( 1, 4 ); - } - if ( RANDOM_LONG( 0, 100 ) < 10 ) - targetYaw = RANDOM_LONG( -30, 30 ); - pTarget = NULL; - // oldorigin test - if ( (pev->origin - pev->oldorigin).Length() < 1 ) - { - // If leech didn't move, there must be something blocking it, so try to turn - m_sideTime = 0; - } - - break; - } - - m_obstacle = ObstacleDistance( pTarget ); - pev->oldorigin = pev->origin; - if ( m_obstacle < 0.1 ) - m_obstacle = 0.1; - - // is the way ahead clear? - if ( m_obstacle == 1.0 ) - { - // if the leech is turning, stop the trend. - if ( m_flTurning != 0 ) - { - m_flTurning = 0; - } - - m_fPathBlocked = FALSE; - pev->speed = UTIL_Approach( targetSpeed, pev->speed, LEECH_SWIM_ACCEL * LEECH_FRAMETIME ); - pev->velocity = gpGlobals->v_forward * pev->speed; - - } - else - { - m_obstacle = 1.0 / m_obstacle; - // IF we get this far in the function, the leader's path is blocked! - m_fPathBlocked = TRUE; - - if ( m_flTurning == 0 )// something in the way and leech is not already turning to avoid - { - Vector vecTest; - // measure clearance on left and right to pick the best dir to turn - vecTest = pev->origin + (gpGlobals->v_right * LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - flRightSide = tr.flFraction; - - vecTest = pev->origin + (gpGlobals->v_right * -LEECH_SIZEX) + (gpGlobals->v_forward * LEECH_CHECK_DIST); - UTIL_TraceLine(pev->origin, vecTest, missile, edict(), &tr); - flLeftSide = tr.flFraction; - - // turn left, right or random depending on clearance ratio - float delta = (flRightSide - flLeftSide); - if ( delta > 0.1 || (delta > -0.1 && RANDOM_LONG(0,100)<50) ) - m_flTurning = -LEECH_TURN_RATE; - else - m_flTurning = LEECH_TURN_RATE; - } - pev->speed = UTIL_Approach( -(LEECH_SWIM_SPEED*0.5), pev->speed, LEECH_SWIM_DECEL * LEECH_FRAMETIME * m_obstacle ); - pev->velocity = gpGlobals->v_forward * pev->speed; - } - pev->ideal_yaw = m_flTurning + targetYaw; - UpdateMotion(); -} - - -void CLeech::Killed(entvars_t *pevAttacker, int iGib) -{ - Vector vecSplatDir; - TraceResult tr; - - //ALERT(at_aiconsole, "Leech: killed\n"); - // tell owner ( if any ) that we're dead.This is mostly for MonsterMaker functionality. - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if (pOwner) - pOwner->DeathNotice(pev); - - // When we hit the ground, play the "death_end" activity - if ( pev->waterlevel ) - { - pev->angles.z = 0; - pev->angles.x = 0; - pev->origin.z += 1; - pev->avelocity = g_vecZero; - if ( RANDOM_LONG( 0, 99 ) < 70 ) - pev->avelocity.y = RANDOM_LONG( -720, 720 ); - - pev->gravity = 0.02; - ClearBits(pev->flags, FL_ONGROUND); - SetActivity( ACT_DIESIMPLE ); - } - else - SetActivity( ACT_DIEFORWARD ); - - pev->movetype = MOVETYPE_TOSS; - pev->takedamage = DAMAGE_NO; - SetThink( &CLeech::DeadThink ); -} - - diff --git a/sdk/dlls/lights.cpp b/sdk/dlls/lights.cpp deleted file mode 100644 index 1053230..0000000 --- a/sdk/dlls/lights.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== lights.cpp ======================================================== - - spawn and think functions for editor-placed lights - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" - - - -class CLight : public CPointEntity -{ -public: - virtual void KeyValue( KeyValueData* pkvd ); - virtual void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iStyle; - int m_iszPattern; -}; -LINK_ENTITY_TO_CLASS( light, CLight ); - -TYPEDESCRIPTION CLight::m_SaveData[] = -{ - DEFINE_FIELD( CLight, m_iStyle, FIELD_INTEGER ), - DEFINE_FIELD( CLight, m_iszPattern, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CLight, CPointEntity ); - - -// -// Cache user-entity-field values until spawn is called. -// -void CLight :: KeyValue( KeyValueData* pkvd) -{ - if (FStrEq(pkvd->szKeyName, "style")) - { - m_iStyle = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - pev->angles.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "pattern")) - { - m_iszPattern = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CPointEntity::KeyValue( pkvd ); - } -} - -/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) LIGHT_START_OFF -Non-displayed light. -Default light value is 300 -Default style is 0 -If targeted, it will toggle between on or off. -*/ - -void CLight :: Spawn( void ) -{ - if (FStringNull(pev->targetname)) - { // inert light - REMOVE_ENTITY(ENT(pev)); - return; - } - - if (m_iStyle >= 32) - { -// CHANGE_METHOD(ENT(pev), em_use, light_use); - if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) - LIGHT_STYLE(m_iStyle, "a"); - else if (m_iszPattern) - LIGHT_STYLE(m_iStyle, STRING( m_iszPattern )); - else - LIGHT_STYLE(m_iStyle, "m"); - } -} - - -void CLight :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (m_iStyle >= 32) - { - if ( !ShouldToggle( useType, !FBitSet(pev->spawnflags, SF_LIGHT_START_OFF) ) ) - return; - - if (FBitSet(pev->spawnflags, SF_LIGHT_START_OFF)) - { - if (m_iszPattern) - LIGHT_STYLE(m_iStyle, STRING( m_iszPattern )); - else - LIGHT_STYLE(m_iStyle, "m"); - ClearBits(pev->spawnflags, SF_LIGHT_START_OFF); - } - else - { - LIGHT_STYLE(m_iStyle, "a"); - SetBits(pev->spawnflags, SF_LIGHT_START_OFF); - } - } -} - -// -// shut up spawn functions for new spotlights -// -LINK_ENTITY_TO_CLASS( light_spot, CLight ); - - -class CEnvLight : public CLight -{ -public: - void KeyValue( KeyValueData* pkvd ); - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( light_environment, CEnvLight ); - -void CEnvLight::KeyValue( KeyValueData* pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "_light")) - { - int r, g, b, v, j; - char szColor[64]; - j = sscanf( pkvd->szValue, "%d %d %d %d\n", &r, &g, &b, &v ); - if (j == 1) - { - g = b = r; - } - else if (j == 4) - { - r = r * (v / 255); - g = g * (v / 255); - b = b * (v / 255); - } - - // simulate qrad direct, ambient,and gamma adjustments, as well as engine scaling - r = static_cast(powf( r / 114.0f, 0.6f ) * 264); - g = static_cast(powf( g / 114.0f, 0.6f ) * 264); - b = static_cast(powf( b / 114.0f, 0.6f ) * 264); - - pkvd->fHandled = TRUE; - sprintf( szColor, "%d", r ); - CVAR_SET_STRING( "sv_skycolor_r", szColor ); - sprintf( szColor, "%d", g ); - CVAR_SET_STRING( "sv_skycolor_g", szColor ); - sprintf( szColor, "%d", b ); - CVAR_SET_STRING( "sv_skycolor_b", szColor ); - } - else - { - CLight::KeyValue( pkvd ); - } -} - - -void CEnvLight :: Spawn( void ) -{ - char szVector[64]; - UTIL_MakeAimVectors( pev->angles ); - - sprintf( szVector, "%f", gpGlobals->v_forward.x ); - CVAR_SET_STRING( "sv_skyvec_x", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.y ); - CVAR_SET_STRING( "sv_skyvec_y", szVector ); - sprintf( szVector, "%f", gpGlobals->v_forward.z ); - CVAR_SET_STRING( "sv_skyvec_z", szVector ); - - CLight::Spawn( ); -} diff --git a/sdk/dlls/maprules.cpp b/sdk/dlls/maprules.cpp deleted file mode 100644 index a07562d..0000000 --- a/sdk/dlls/maprules.cpp +++ /dev/null @@ -1,918 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// ------------------------------------------- -// -// maprules.cpp -// -// This module contains entities for implementing/changing game -// rules dynamically within each map (.BSP) -// -// ------------------------------------------- - -#include "extdll.h" -#include "eiface.h" -#include "util.h" -#include "gamerules.h" -#include "maprules.h" -#include "cbase.h" -#include "player.h" - -class CRuleEntity : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } - -protected: - BOOL CanFireForActivator( CBaseEntity *pActivator ); - -private: - string_t m_iszMaster; -}; - -TYPEDESCRIPTION CRuleEntity::m_SaveData[] = -{ - DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), -}; - -IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ); - - -void CRuleEntity::Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->effects = EF_NODRAW; -} - - -void CRuleEntity::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - SetMaster( ALLOC_STRING(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) -{ - if ( m_iszMaster ) - { - if ( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) - return TRUE; - else - return FALSE; - } - - return TRUE; -} - -// -// CRulePointEntity -- base class for all rule "point" entities (not brushes) -// -class CRulePointEntity : public CRuleEntity -{ -public: - void Spawn( void ); -}; - -void CRulePointEntity::Spawn( void ) -{ - CRuleEntity::Spawn(); - pev->frame = 0; - pev->model = 0; -} - -// -// CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) -// Default behavior is to set up like a trigger, invisible, but keep the model for volume testing -// -class CRuleBrushEntity : public CRuleEntity -{ -public: - void Spawn( void ); - -private: -}; - -void CRuleBrushEntity::Spawn( void ) -{ - SET_MODEL( edict(), STRING(pev->model) ); - CRuleEntity::Spawn(); -} - - -// CGameScore / game_score -- award points to player / team -// Points +/- total -// Flag: Allow negative scores SF_SCORE_NEGATIVE -// Flag: Award points to team in teamplay SF_SCORE_TEAM - -#define SF_SCORE_NEGATIVE 0x0001 -#define SF_SCORE_TEAM 0x0002 - -class CGameScore : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - inline int Points( void ) { return static_cast(pev->frags); } - inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } - inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } - - inline void SetPoints( int points ) { pev->frags = points; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_score, CGameScore ); - - -void CGameScore::Spawn( void ) -{ - CRulePointEntity::Spawn(); -} - - -void CGameScore::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "points")) - { - SetPoints( atoi(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - - -void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - // Only players can use this - if ( pActivator->IsPlayer() ) - { - if ( AwardToTeam() ) - { - pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); - } - else - { - pActivator->AddPoints( Points(), AllowNegativeScore() ); - } - } -} - - -// CGameEnd / game_end -- Ends the game in MP - -class CGameEnd : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -private: -}; - -LINK_ENTITY_TO_CLASS( game_end, CGameEnd ); - - -void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - g_pGameRules->EndMultiplayerGame(); -} - - -// -// CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) -// Flag: All players SF_ENVTEXT_ALLPLAYERS -// - - -#define SF_ENVTEXT_ALLPLAYERS 0x0001 - - -class CGameText : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } - inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } - inline const char *MessageGet( void ) { return STRING(pev->message); } - -private: - - hudtextparms_t m_textParms; -}; - -LINK_ENTITY_TO_CLASS( game_text, CGameText ); - -// Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so -// it can't impact saved Half-Life games. -TYPEDESCRIPTION CGameText::m_SaveData[] = -{ - DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), -}; - -IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ); - - -void CGameText::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "channel")) - { - m_textParms.channel = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "x")) - { - m_textParms.x = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "y")) - { - m_textParms.y = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "effect")) - { - m_textParms.effect = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r1 = color[0]; - m_textParms.g1 = color[1]; - m_textParms.b1 = color[2]; - m_textParms.a1 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "color2")) - { - int color[4]; - UTIL_StringToIntArray( color, 4, pkvd->szValue ); - m_textParms.r2 = color[0]; - m_textParms.g2 = color[1]; - m_textParms.b2 = color[2]; - m_textParms.a2 = color[3]; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_textParms.fadeinTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_textParms.fadeoutTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - m_textParms.holdTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "fxtime")) - { - m_textParms.fxTime = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( MessageToAll() ) - { - UTIL_HudMessageAll( m_textParms, MessageGet() ); - } - else - { - if ( pActivator->IsNetClient() ) - { - UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); - } - } -} - - -// -// CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator -// Only allows mastered entity to fire if the team matches my team -// -// team index (pulled from server team list "mp_teamlist" -// Flag: Remove on Fire -// Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) -// - -#define SF_TEAMMASTER_FIREONCE 0x0001 -#define SF_TEAMMASTER_ANYTEAM 0x0002 - -class CGameTeamMaster : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } - - BOOL IsTriggered( CBaseEntity *pActivator ); - const char *TeamID( void ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } - inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } - -private: - BOOL TeamMatch( CBaseEntity *pActivator ); - - int m_teamIndex; - USE_TYPE triggerType; -}; - -LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ); - -void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "teamindex")) - { - m_teamIndex = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CRulePointEntity::KeyValue( pkvd ); -} - - -void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( useType == USE_SET ) - { - if ( value < 0 ) - { - m_teamIndex = -1; - } - else - { - m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); - } - return; - } - - if ( TeamMatch( pActivator ) ) - { - SUB_UseTargets( pActivator, triggerType, value ); - if ( RemoveOnFire() ) - UTIL_Remove( this ); - } -} - - -BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) -{ - return TeamMatch( pActivator ); -} - - -const char *CGameTeamMaster::TeamID( void ) -{ - if ( m_teamIndex < 0 ) // Currently set to "no team" - return ""; - - return g_pGameRules->GetIndexedTeamName( m_teamIndex ); // UNDONE: Fill this in with the team from the "teamlist" -} - - -BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) -{ - if ( m_teamIndex < 0 && AnyTeam() ) - return TRUE; - - if ( !pActivator ) - return FALSE; - - return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); -} - - -// -// CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team -// Flag: Fire once -// Flag: Clear team -- Sets the team to "NONE" instead of activator - -#define SF_TEAMSET_FIREONCE 0x0001 -#define SF_TEAMSET_CLEARTEAM 0x0002 - -class CGameTeamSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ); - - -void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( ShouldClearTeam() ) - { - SUB_UseTargets( pActivator, USE_SET, -1 ); - } - else - { - SUB_UseTargets( pActivator, USE_SET, 0 ); - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired -// -// Needs master? -class CGamePlayerZone : public CRuleBrushEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - string_t m_iszInTarget; - string_t m_iszOutTarget; - string_t m_iszInCount; - string_t m_iszOutCount; -}; - -LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ); -TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = -{ - DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), - DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ); - -void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "intarget")) - { - m_iszInTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outtarget")) - { - m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "incount")) - { - m_iszInCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "outcount")) - { - m_iszOutCount = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CRuleBrushEntity::KeyValue( pkvd ); -} - -void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int playersInCount = 0; - int playersOutCount = 0; - - if ( !CanFireForActivator( pActivator ) ) - return; - - CBaseEntity *pPlayer = NULL; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - { - TraceResult trace; - int hullNumber; - - hullNumber = human_hull; - if ( pPlayer->pev->flags & FL_DUCKING ) - { - hullNumber = head_hull; - } - - UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); - - if ( trace.fStartSolid ) - { - playersInCount++; - if ( m_iszInTarget ) - { - FireTargets( STRING(m_iszInTarget), pPlayer, pActivator, useType, value ); - } - } - else - { - playersOutCount++; - if ( m_iszOutTarget ) - { - FireTargets( STRING(m_iszOutTarget), pPlayer, pActivator, useType, value ); - } - } - } - } - - if ( m_iszInCount ) - { - FireTargets( STRING(m_iszInCount), pActivator, this, USE_SET, playersInCount ); - } - - if ( m_iszOutCount ) - { - FireTargets( STRING(m_iszOutCount), pActivator, this, USE_SET, playersOutCount ); - } -} - - - -// -// CGamePlayerHurt / game_player_hurt -- Damages the player who fires it -// Flag: Fire once - -#define SF_PKILL_FIREONCE 0x0001 -class CGamePlayerHurt : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ); - - -void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - if ( pev->dmg < 0 ) - pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); - else - pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); - } - - SUB_UseTargets( pActivator, useType, value ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - - -// -// CGameCounter / game_counter -- Counts events and fires target -// Flag: Fire once -// Flag: Reset on Fire - -#define SF_GAMECOUNT_FIREONCE 0x0001 -#define SF_GAMECOUNT_RESET 0x0002 - -class CGameCounter : public CRulePointEntity -{ -public: - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } - inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } - - inline void CountUp( void ) { pev->frags++; } - inline void CountDown( void ) { pev->frags--; } - inline void ResetCount( void ) { pev->frags = pev->dmg; } - inline int CountValue( void ) { return static_cast(pev->frags); } - inline int LimitValue( void ) { return static_cast(pev->health); } - - inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } - -private: - - inline void SetCountValue( int value ) { pev->frags = value; } - inline void SetInitialValue( int value ) { pev->dmg = value; } -}; - -LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ); - -void CGameCounter::Spawn( void ) -{ - // Save off the initial count - SetInitialValue( CountValue() ); - CRulePointEntity::Spawn(); -} - - -void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - switch( useType ) - { - case USE_ON: - case USE_TOGGLE: - CountUp(); - break; - - case USE_OFF: - CountDown(); - break; - - case USE_SET: - SetCountValue( (int)value ); - break; - } - - if ( HitLimit() ) - { - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } - - if ( ResetOnFire() ) - { - ResetCount(); - } - } -} - - - -// -// CGameCounterSet / game_counter_set -- Sets the counter's value -// Flag: Fire once - -#define SF_GAMECOUNTSET_FIREONCE 0x0001 - -class CGameCounterSet : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } - -private: -}; - -LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ); - - -void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - SUB_UseTargets( pActivator, USE_SET, pev->frags ); - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - -// -// CGamePlayerEquip / game_playerequip -- Sets the default player equipment -// Flag: USE Only - -#define SF_PLAYEREQUIP_USEONLY 0x0001 -#define MAX_EQUIP 32 - -class CGamePlayerEquip : public CRulePointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } - -private: - - void EquipPlayer( CBaseEntity *pPlayer ); - - string_t m_weaponNames[MAX_EQUIP]; - int m_weaponCount[MAX_EQUIP]; -}; - -LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ); - - -void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) -{ - CRulePointEntity::KeyValue( pkvd ); - - if ( !pkvd->fHandled ) - { - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - - m_weaponNames[i] = ALLOC_STRING(tmp); - m_weaponCount[i] = atoi(pkvd->szValue); - m_weaponCount[i] = max(1,m_weaponCount[i]); - pkvd->fHandled = TRUE; - break; - } - } - } -} - - -void CGamePlayerEquip::Touch( CBaseEntity *pOther ) -{ - if ( !CanFireForActivator( pOther ) ) - return; - - if ( UseOnly() ) - return; - - EquipPlayer( pOther ); -} - -void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pEntity->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pEntity; - } - - if ( !pPlayer ) - return; - - for ( int i = 0; i < MAX_EQUIP; i++ ) - { - if ( !m_weaponNames[i] ) - break; - for ( int j = 0; j < m_weaponCount[i]; j++ ) - { - pPlayer->GiveNamedItem( STRING(m_weaponNames[i]) ); - } - } -} - - -void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - EquipPlayer( pActivator ); -} - - -// -// CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it -// Flag: Fire once -// Flag: Kill Player -// Flag: Gib Player - -#define SF_PTEAM_FIREONCE 0x0001 -#define SF_PTEAM_KILL 0x0002 -#define SF_PTEAM_GIB 0x0004 - -class CGamePlayerTeam : public CRulePointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: - - inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } - inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } - inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } - - const char *TargetTeamName( const char *pszTargetName ); -}; - -LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ); - - -const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) -{ - CBaseEntity *pTeamEntity = NULL; - - while ((pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName )) != NULL) - { - if ( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) - return pTeamEntity->TeamID(); - } - - return NULL; -} - - -void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !CanFireForActivator( pActivator ) ) - return; - - if ( pActivator->IsPlayer() ) - { - const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); - if ( pszTargetTeam ) - { - CBasePlayer *pPlayer = (CBasePlayer *)pActivator; - g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); - } - } - - if ( RemoveOnFire() ) - { - UTIL_Remove( this ); - } -} - - diff --git a/sdk/dlls/maprules.h b/sdk/dlls/maprules.h deleted file mode 100644 index 57f9939..0000000 --- a/sdk/dlls/maprules.h +++ /dev/null @@ -1,22 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef MAPRULES_H -#define MAPRULES_H - - - -#endif // MAPRULES_H - diff --git a/sdk/dlls/monsterevent.h b/sdk/dlls/monsterevent.h deleted file mode 100644 index 46c5624..0000000 --- a/sdk/dlls/monsterevent.h +++ /dev/null @@ -1,34 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef MONSTEREVENT_H -#define MONSTEREVENT_H - -typedef struct -{ - int event; - char *options; -} MonsterEvent_t; - -#define EVENT_SPECIFIC 0 -#define EVENT_SCRIPTED 1000 -#define EVENT_SHARED 2000 -#define EVENT_CLIENT 5000 - -#define MONSTER_EVENT_BODYDROP_LIGHT 2001 -#define MONSTER_EVENT_BODYDROP_HEAVY 2002 - -#define MONSTER_EVENT_SWISHSOUND 2010 - -#endif // MONSTEREVENT_H diff --git a/sdk/dlls/monstermaker.cpp b/sdk/dlls/monstermaker.cpp deleted file mode 100644 index 8fa7e44..0000000 --- a/sdk/dlls/monstermaker.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Monster Maker - this is an entity that creates monsters -// in the game. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "saverestore.h" - -// Monstermaker spawnflags -#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname ) -#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired. -#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip - -//========================================================= -// MonsterMaker - this ent creates monsters during the game. -//========================================================= -class CMonsterMaker : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData* pkvd); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MakerThink ( void ); - void DeathNotice ( entvars_t *pevChild );// monster maker children use this to tell the monster maker that they have died. - void MakeMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. - - int m_cNumMonsters;// max number of monsters this ent can create - - - int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive - int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. - - float m_flGround; // z coord of the ground under me, used to make sure no monsters are under the maker when it drops a new child - - BOOL m_fActive; - BOOL m_fFadeChildren;// should we make the children fadeout? -}; - -LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker ); - -TYPEDESCRIPTION CMonsterMaker::m_SaveData[] = -{ - DEFINE_FIELD( CMonsterMaker, m_iszMonsterClassname, FIELD_STRING ), - DEFINE_FIELD( CMonsterMaker, m_cNumMonsters, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_cLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_flGround, FIELD_FLOAT ), - DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ), - DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ), -}; - - -IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster ); - -void CMonsterMaker :: KeyValue( KeyValueData *pkvd ) -{ - - if ( FStrEq(pkvd->szKeyName, "monstercount") ) - { - m_cNumMonsters = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "m_imaxlivechildren") ) - { - m_iMaxLiveChildren = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "monstertype") ) - { - m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CMonsterMaker :: Spawn( ) -{ - pev->solid = SOLID_NOT; - - m_cLiveChildren = 0; - Precache(); - if ( !FStringNull ( pev->targetname ) ) - { - if ( pev->spawnflags & SF_MONSTERMAKER_CYCLIC ) - { - SetUse ( &CMonsterMaker::CyclicUse );// drop one monster each time we fire - } - else - { - SetUse ( &CMonsterMaker::ToggleUse );// so can be turned on/off - } - - if ( FBitSet ( pev->spawnflags, SF_MONSTERMAKER_START_ON ) ) - {// start making monsters as soon as monstermaker spawns - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - else - {// wait to be activated. - m_fActive = FALSE; - SetThink ( &CMonsterMaker::SUB_DoNothing ); - } - } - else - {// no targetname, just start. - pev->nextthink = gpGlobals->time + m_flDelay; - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - - if ( m_cNumMonsters == 1 ) - { - m_fFadeChildren = FALSE; - } - else - { - m_fFadeChildren = TRUE; - } - - m_flGround = 0; -} - -void CMonsterMaker :: Precache( void ) -{ - CBaseMonster::Precache(); - - UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) ); -} - -//========================================================= -// MakeMonster- this is the code that drops the monster -//========================================================= -void CMonsterMaker::MakeMonster( void ) -{ - edict_t *pent; - entvars_t *pevCreate; - - if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren ) - {// not allowed to make a new one yet. Too many live ones out right now. - return; - } - - if ( !m_flGround ) - { - // set altitude. Now that I'm activated, any breakables, etc should be out from under me. - TraceResult tr; - - UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr ); - m_flGround = tr.vecEndPos.z; - } - - Vector mins = pev->origin - Vector( 34, 34, 0 ); - Vector maxs = pev->origin + Vector( 34, 34, 0 ); - maxs.z = pev->origin.z; - mins.z = m_flGround; - - CBaseEntity *pList[2]; - int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER ); - if ( count ) - { - // don't build a stack of monsters! - return; - } - - pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname ); - - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in MonsterMaker!\n" ); - return; - } - - // If I have a target, fire! - if ( !FStringNull ( pev->target ) ) - { - // delay already overloaded for this entity, so can't call SUB_UseTargets() - FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 ); - } - - pevCreate = VARS( pent ); - pevCreate->origin = pev->origin; - pevCreate->angles = pev->angles; - SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND ); - - // Children hit monsterclip brushes - if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP ) - SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP ); - - DispatchSpawn( ENT( pevCreate ) ); - pevCreate->owner = edict(); - - if ( !FStringNull( pev->netname ) ) - { - // if I have a netname (overloaded), give the child monster that name as a targetname - pevCreate->targetname = pev->netname; - } - - m_cLiveChildren++;// count this monster - m_cNumMonsters--; - - if ( m_cNumMonsters == 0 ) - { - // Disable this forever. Don't kill it because it still gets death notices - SetThink( NULL ); - SetUse( NULL ); - } -} - -//========================================================= -// CyclicUse - drops one monster from the monstermaker -// each time we call this. -//========================================================= -void CMonsterMaker::CyclicUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - MakeMonster(); -} - -//========================================================= -// ToggleUse - activates/deactivates the monster maker -//========================================================= -void CMonsterMaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_fActive ) ) - return; - - if ( m_fActive ) - { - m_fActive = FALSE; - SetThink ( NULL ); - } - else - { - m_fActive = TRUE; - SetThink ( &CMonsterMaker::MakerThink ); - } - - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// MakerThink - creates a new monster every so often -//========================================================= -void CMonsterMaker :: MakerThink ( void ) -{ - pev->nextthink = gpGlobals->time + m_flDelay; - - MakeMonster(); -} - - -//========================================================= -//========================================================= -void CMonsterMaker :: DeathNotice ( entvars_t *pevChild ) -{ - // ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade. - m_cLiveChildren--; - - if ( !m_fFadeChildren ) - { - pevChild->owner = NULL; - } -} - - diff --git a/sdk/dlls/monsters.cpp b/sdk/dlls/monsters.cpp deleted file mode 100644 index ec353f4..0000000 --- a/sdk/dlls/monsters.cpp +++ /dev/null @@ -1,3448 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== monsters.cpp ======================================================== - - Monster-related utility code - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "weapons.h" -#include "scripted.h" -#include "squadmonster.h" -#include "decals.h" -#include "soundent.h" -#include "gamerules.h" - -#define MONSTER_CUT_CORNER_DIST 8 // 8 means the monster's bounding box is contained without the box of the node in WC - - -Vector VecBModelOrigin( entvars_t* pevBModel ); - -extern DLL_GLOBAL BOOL g_fDrawLines; -extern DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -extern DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot - -extern CGraph WorldGraph;// the world node graph - - - -// Global Savedata for monster -// UNDONE: Save schedule data? Can this be done? We may -// lose our enemy pointer or other data (goal ent, target, etc) -// that make the current schedule invalid, perhaps it's best -// to just pick a new one when we start up again. -TYPEDESCRIPTION CBaseMonster::m_SaveData[] = -{ - DEFINE_FIELD( CBaseMonster, m_hEnemy, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseMonster, m_hTargetEnt, FIELD_EHANDLE ), - DEFINE_ARRAY( CBaseMonster, m_hOldEnemy, FIELD_EHANDLE, MAX_OLD_ENEMIES ), - DEFINE_ARRAY( CBaseMonster, m_vecOldEnemy, FIELD_POSITION_VECTOR, MAX_OLD_ENEMIES ), - DEFINE_FIELD( CBaseMonster, m_flFieldOfView, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flWaitFinished, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_flMoveWaitFinished, FIELD_TIME ), - - DEFINE_FIELD( CBaseMonster, m_Activity, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_IdealActivity, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_LastHitGroup, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_MonsterState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_IdealMonsterState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iTaskStatus, FIELD_INTEGER ), - - //Schedule_t *m_pSchedule; - - DEFINE_FIELD( CBaseMonster, m_iScheduleIndex, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afConditions, FIELD_INTEGER ), - //WayPoint_t m_Route[ ROUTE_SIZE ]; -// DEFINE_FIELD( CBaseMonster, m_movementGoal, FIELD_INTEGER ), -// DEFINE_FIELD( CBaseMonster, m_iRouteIndex, FIELD_INTEGER ), -// DEFINE_FIELD( CBaseMonster, m_moveWaitTime, FIELD_FLOAT ), - - DEFINE_FIELD( CBaseMonster, m_vecMoveGoal, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_movementActivity, FIELD_INTEGER ), - - // int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. -// DEFINE_FIELD( CBaseMonster, m_afSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_vecLastPosition, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_iHintNode, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afMemory, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iMaxHealth, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_vecEnemyLKP, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseMonster, m_cAmmoLoaded, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_afCapability, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_flNextAttack, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_bitsDamageType, FIELD_INTEGER ), - DEFINE_ARRAY( CBaseMonster, m_rgbTimeBasedDamage, FIELD_CHARACTER, CDMG_TIMEBASED ), - DEFINE_FIELD( CBaseMonster, m_bloodColor, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_failSchedule, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseMonster, m_flHungryTime, FIELD_TIME ), - DEFINE_FIELD( CBaseMonster, m_flDistTooFar, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_flDistLook, FIELD_FLOAT ), - DEFINE_FIELD( CBaseMonster, m_iTriggerCondition, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_iszTriggerTarget, FIELD_STRING ), - - DEFINE_FIELD( CBaseMonster, m_HackedGunPos, FIELD_VECTOR ), - - DEFINE_FIELD( CBaseMonster, m_scriptState, FIELD_INTEGER ), - DEFINE_FIELD( CBaseMonster, m_pCine, FIELD_CLASSPTR ), -}; - -//IMPLEMENT_SAVERESTORE( CBaseMonster, CBaseToggle ); -int CBaseMonster::Save( CSave &save ) -{ - if ( !CBaseToggle::Save(save) ) - return 0; - return save.WriteFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); -} - -int CBaseMonster::Restore( CRestore &restore ) -{ - if ( !CBaseToggle::Restore(restore) ) - return 0; - int status = restore.ReadFields( "CBaseMonster", this, m_SaveData, ARRAYSIZE(m_SaveData) ); - - // We don't save/restore routes yet - RouteClear(); - - // We don't save/restore schedules yet - m_pSchedule = NULL; - m_iTaskStatus = TASKSTATUS_NEW; - - // Reset animation - m_Activity = ACT_RESET; - - // If we don't have an enemy, clear conditions like see enemy, etc. - if ( m_hEnemy == 0 ) - m_afConditions = 0; - - return status; -} - - -//========================================================= -// Eat - makes a monster full for a little while. -//========================================================= -void CBaseMonster :: Eat ( float flFullDuration ) -{ - m_flHungryTime = gpGlobals->time + flFullDuration; -} - -//========================================================= -// FShouldEat - returns true if a monster is hungry. -//========================================================= -BOOL CBaseMonster :: FShouldEat ( void ) -{ - if ( m_flHungryTime > gpGlobals->time ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - called -// by Barnacle victims when the barnacle pulls their head -// into its mouth -//========================================================= -void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( SCHED_BARNACLE_VICTIM_CHOMP ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } -} - -//========================================================= -// BarnacleVictimReleased - called by barnacle victims when -// the host barnacle is killed. -//========================================================= -void CBaseMonster :: BarnacleVictimReleased ( void ) -{ - m_IdealMonsterState = MONSTERSTATE_IDLE; - - pev->velocity = g_vecZero; - pev->movetype = MOVETYPE_STEP; -} - -//========================================================= -// Listen - monsters dig through the active sound list for -// any sounds that may interest them. (smells, too!) -//========================================================= -void CBaseMonster :: Listen ( void ) -{ - int iSound; - int iMySounds; - float hearingSensitivity; - CSound *pCurrentSound; - - m_iAudibleList = SOUNDLIST_EMPTY; - ClearConditions(bits_COND_HEAR_SOUND | bits_COND_SMELL | bits_COND_SMELL_FOOD); - m_afSoundTypes = 0; - - iMySounds = ISoundMask(); - - if ( m_pSchedule ) - { - //!!!WATCH THIS SPOT IF YOU ARE HAVING SOUND RELATED BUGS! - // Make sure your schedule AND personal sound masks agree! - iMySounds &= m_pSchedule->iSoundMask; - } - - iSound = CSoundEnt::ActiveList(); - - // UNDONE: Clear these here? - ClearConditions( bits_COND_HEAR_SOUND | bits_COND_SMELL_FOOD | bits_COND_SMELL ); - hearingSensitivity = HearingSensitivity( ); - - while ( iSound != SOUNDLIST_EMPTY ) - { - pCurrentSound = CSoundEnt::SoundPointerForIndex( iSound ); - - if ( pCurrentSound && - ( pCurrentSound->m_iType & iMySounds ) && - ( pCurrentSound->m_vecOrigin - EarPosition() ).Length() <= pCurrentSound->m_iVolume * hearingSensitivity ) - - //if ( ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & iMySounds ) && ( g_pSoundEnt->m_SoundPool[ iSound ].m_vecOrigin - EarPosition()).Length () <= g_pSoundEnt->m_SoundPool[ iSound ].m_iVolume * hearingSensitivity ) - { - // the monster cares about this sound, and it's close enough to hear. - //g_pSoundEnt->m_SoundPool[ iSound ].m_iNextAudible = m_iAudibleList; - pCurrentSound->m_iNextAudible = m_iAudibleList; - - if ( pCurrentSound->FIsSound() ) - { - // this is an audible sound. - SetConditions( bits_COND_HEAR_SOUND ); - } - else - { - // if not a sound, must be a smell - determine if it's just a scent, or if it's a food scent -// if ( g_pSoundEnt->m_SoundPool[ iSound ].m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) - if ( pCurrentSound->m_iType & ( bits_SOUND_MEAT | bits_SOUND_CARCASS ) ) - { - // the detected scent is a food item, so set both conditions. - // !!!BUGBUG - maybe a virtual function to determine whether or not the scent is food? - SetConditions( bits_COND_SMELL_FOOD ); - SetConditions( bits_COND_SMELL ); - } - else - { - // just a normal scent. - SetConditions( bits_COND_SMELL ); - } - } - -// m_afSoundTypes |= g_pSoundEnt->m_SoundPool[ iSound ].m_iType; - m_afSoundTypes |= pCurrentSound->m_iType; - - m_iAudibleList = iSound; - } - -// iSound = g_pSoundEnt->m_SoundPool[ iSound ].m_iNext; - iSound = pCurrentSound->m_iNext; - } -} - -//========================================================= -// FLSoundVolume - subtracts the volume of the given sound -// from the distance the sound source is from the caller, -// and returns that value, which is considered to be the 'local' -// volume of the sound. -//========================================================= -float CBaseMonster :: FLSoundVolume ( CSound *pSound ) -{ - return ( pSound->m_iVolume - ( ( pSound->m_vecOrigin - pev->origin ).Length() ) ); -} - -//========================================================= -// FValidateHintType - tells use whether or not the monster cares -// about the type of Hint Node given -//========================================================= -BOOL CBaseMonster :: FValidateHintType ( short sHint ) -{ - return FALSE; -} - -//========================================================= -// Look - Base class monster function to find enemies or -// food by sight. iDistance is distance ( in units ) that the -// monster can see. -// -// Sets the sight bits of the m_afConditions mask to indicate -// which types of entities were sighted. -// Function also sets the Looker's m_pLink -// to the head of a link list that contains all visible ents. -// (linked via each ent's m_pLink field) -// -//========================================================= -void CBaseMonster :: Look ( int iDistance ) -{ - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); - - m_pLink = NULL; - - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - - // See no evil if prisoner is set - if ( !FBitSet( pev->spawnflags, SF_MONSTER_PRISONER ) ) - { - CBaseEntity *pList[100]; - - Vector delta = Vector( iDistance, iDistance, iDistance ); - - // Find only monsters/clients in box, NOT limited to PVS - int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - pSightEnt = pList[i]; - // !!!temporarily only considering other monsters and clients, don't see prisoners - if ( pSightEnt != this && - !FBitSet( pSightEnt->pev->spawnflags, SF_MONSTER_PRISONER ) && - pSightEnt->pev->health > 0 ) - { - // the looker will want to consider this entity - // don't check anything else about an entity that can't be seen, or an entity that you don't care about. - if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) - { - if ( pSightEnt->IsPlayer() ) - { - if ( pev->spawnflags & SF_MONSTER_WAIT_TILL_SEEN ) - { - CBaseMonster *pClient; - - pClient = pSightEnt->MyMonsterPointer(); - // don't link this client in the list if the monster is wait till seen and the player isn't facing the monster - if ( pSightEnt && !pClient->FInViewCone( this ) ) - { - // we're not in the player's view cone. - continue; - } - else - { - // player sees us, become normal now. - pev->spawnflags &= ~SF_MONSTER_WAIT_TILL_SEEN; - } - } - - // if we see a client, remember that (mostly for scripted AI) - iSighted |= bits_COND_SEE_CLIENT; - } - - pSightEnt->m_pLink = m_pLink; - m_pLink = pSightEnt; - - if ( pSightEnt == m_hEnemy ) - { - // we know this ent is visible, so if it also happens to be our enemy, store that now. - iSighted |= bits_COND_SEE_ENEMY; - } - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_NM: - iSighted |= bits_COND_SEE_NEMESIS; - break; - case R_HT: - iSighted |= bits_COND_SEE_HATE; - break; - case R_DL: - iSighted |= bits_COND_SEE_DISLIKE; - break; - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_AL: - break; - default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - } - - SetConditions( iSighted ); -} - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CBaseMonster :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER; -} - -//========================================================= -// PBestSound - returns a pointer to the sound the monster -// should react to. Right now responds only to nearest sound. -//========================================================= -CSound* CBaseMonster :: PBestSound ( void ) -{ - int iThisSound; - int iBestSound = -1; - float flBestDist = 8192;// so first nearby sound will become best so far. - float flDist; - CSound *pSound; - - iThisSound = m_iAudibleList; - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_aiconsole, "ERROR! monster %s has no audible sounds!\n", STRING(pev->classname) ); -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; - } - - while ( iThisSound != SOUNDLIST_EMPTY ) - { - pSound = CSoundEnt::SoundPointerForIndex( iThisSound ); - - if ( pSound && pSound->FIsSound() ) - { - flDist = ( pSound->m_vecOrigin - EarPosition()).Length(); - - if ( flDist < flBestDist ) - { - iBestSound = iThisSound; - flBestDist = flDist; - } - } - - iThisSound = pSound->m_iNextAudible; - } - if ( iBestSound >= 0 ) - { - pSound = CSoundEnt::SoundPointerForIndex( iBestSound ); - return pSound; - } -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; -} - -//========================================================= -// PBestScent - returns a pointer to the scent the monster -// should react to. Right now responds only to nearest scent -//========================================================= -CSound* CBaseMonster :: PBestScent ( void ) -{ - int iThisScent; - int iBestScent = -1; - float flBestDist = 8192;// so first nearby smell will become best so far. - float flDist; - CSound *pSound; - - iThisScent = m_iAudibleList;// smells are in the sound list. - - if ( iThisScent == SOUNDLIST_EMPTY ) - { - ALERT ( at_aiconsole, "ERROR! PBestScent() has empty soundlist!\n" ); -#if _DEBUG - ALERT( at_error, "NULL Return from PBestSound\n" ); -#endif - return NULL; - } - - while ( iThisScent != SOUNDLIST_EMPTY ) - { - pSound = CSoundEnt::SoundPointerForIndex( iThisScent ); - - if ( pSound->FIsScent() ) - { - flDist = ( pSound->m_vecOrigin - pev->origin ).Length(); - - if ( flDist < flBestDist ) - { - iBestScent = iThisScent; - flBestDist = flDist; - } - } - - iThisScent = pSound->m_iNextAudible; - } - if ( iBestScent >= 0 ) - { - pSound = CSoundEnt::SoundPointerForIndex( iBestScent ); - - return pSound; - } -#if _DEBUG - ALERT( at_error, "NULL Return from PBestScent\n" ); -#endif - return NULL; -} - - - -//========================================================= -// Monster Think - calls out to core AI functions and handles this -// monster's specific animation events -//========================================================= -void CBaseMonster :: MonsterThink ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking. - - - RunAI(); - - float flInterval = StudioFrameAdvance( ); // animate -// start or end a fidget -// This needs a better home -- switching animations over time should be encapsulated on a per-activity basis -// perhaps MaintainActivity() or a ShiftAnimationOverTime() or something. - if ( m_MonsterState != MONSTERSTATE_SCRIPT && m_MonsterState != MONSTERSTATE_DEAD && m_Activity == ACT_IDLE && m_fSequenceFinished ) - { - int iSequence; - - if ( m_fSequenceLoops ) - { - // animation does loop, which means we're playing subtle idle. Might need to - // fidget. - iSequence = LookupActivity ( m_Activity ); - } - else - { - // animation that just ended doesn't loop! That means we just finished a fidget - // and should return to our heaviest weighted idle (the subtle one) - iSequence = LookupActivityHeaviest ( m_Activity ); - } - if ( iSequence != ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = iSequence; // Set to new anim (if it's there) - ResetSequenceInfo( ); - } - } - - DispatchAnimEvents( flInterval ); - - if ( !MovementIsComplete() ) - { - Move( flInterval ); - } -#if _DEBUG - else - { - if ( !TaskIsRunning() && !TaskIsComplete() ) - ALERT( at_error, "Schedule stalled!!\n" ); - } -#endif -} - -//========================================================= -// CBaseMonster - USE - will make a monster angry at whomever -// activated it. -//========================================================= -void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_IdealMonsterState = MONSTERSTATE_ALERT; -} - -//========================================================= -// Ignore conditions - before a set of conditions is allowed -// to interrupt a monster's schedule, this function removes -// conditions that we have flagged to interrupt the current -// schedule, but may not want to interrupt the schedule every -// time. (Pain, for instance) -//========================================================= -int CBaseMonster :: IgnoreConditions ( void ) -{ - int iIgnoreConditions = 0; - - if ( !FShouldEat() ) - { - // not hungry? Ignore food smell. - iIgnoreConditions |= bits_COND_SMELL_FOOD; - } - - if ( m_MonsterState == MONSTERSTATE_SCRIPT && m_pCine ) - iIgnoreConditions |= m_pCine->IgnoreConditions(); - - return iIgnoreConditions; -} - -//========================================================= -// RouteClear - zeroes out the monster's route array and goal -//========================================================= -void CBaseMonster :: RouteClear ( void ) -{ - RouteNew(); - m_movementGoal = MOVEGOAL_NONE; - m_movementActivity = ACT_IDLE; - Forget( bits_MEMORY_MOVE_FAILED ); -} - -//========================================================= -// Route New - clears out a route to be changed, but keeps -// goal intact. -//========================================================= -void CBaseMonster :: RouteNew ( void ) -{ - m_Route[ 0 ].iType = 0; - m_iRouteIndex = 0; -} - -//========================================================= -// FRouteClear - returns TRUE is the Route is cleared out -// ( invalid ) -//========================================================= -BOOL CBaseMonster :: FRouteClear ( void ) -{ - if ( m_Route[ m_iRouteIndex ].iType == 0 || m_movementGoal == MOVEGOAL_NONE ) - return TRUE; - - return FALSE; -} - -//========================================================= -// FRefreshRoute - after calculating a path to the monster's -// target, this function copies as many waypoints as possible -// from that path to the monster's Route array -//========================================================= -BOOL CBaseMonster :: FRefreshRoute ( void ) -{ - CBaseEntity *pPathCorner; - int i; - BOOL returnCode; - - RouteNew(); - - returnCode = FALSE; - - switch( m_movementGoal ) - { - case MOVEGOAL_PATHCORNER: - { - // monster is on a path_corner loop - pPathCorner = m_pGoalEnt; - i = 0; - - while ( pPathCorner && i < ROUTE_SIZE ) - { - m_Route[ i ].iType = bits_MF_TO_PATHCORNER; - m_Route[ i ].vecLocation = pPathCorner->pev->origin; - - pPathCorner = pPathCorner->GetNextTarget(); - - // Last path_corner in list? - if ( !pPathCorner ) - m_Route[i].iType |= bits_MF_IS_GOAL; - - i++; - } - } - returnCode = TRUE; - break; - - case MOVEGOAL_ENEMY: - returnCode = BuildRoute( m_vecEnemyLKP, bits_MF_TO_ENEMY, m_hEnemy ); - break; - - case MOVEGOAL_LOCATION: - returnCode = BuildRoute( m_vecMoveGoal, bits_MF_TO_LOCATION, NULL ); - break; - - case MOVEGOAL_TARGETENT: - if (m_hTargetEnt != 0) - { - returnCode = BuildRoute( m_hTargetEnt->pev->origin, bits_MF_TO_TARGETENT, m_hTargetEnt ); - } - break; - - case MOVEGOAL_NODE: - returnCode = FGetNodeRoute( m_vecMoveGoal ); -// if ( returnCode ) -// RouteSimplify( NULL ); - break; - } - - return returnCode; -} - - -BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_ENEMY; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_LOCATION; - m_vecMoveGoal = goal; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_TARGETENT; - return FRefreshRoute(); -} - - -BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) -{ - m_movementActivity = movementAct; - m_moveWaitTime = waitTime; - - m_movementGoal = MOVEGOAL_NODE; - m_vecMoveGoal = goal; - return FRefreshRoute(); -} - - -#ifdef _DEBUG -void DrawRoute( entvars_t *pev, WayPoint_t *m_Route, int m_iRouteIndex, int r, int g, int b ) -{ - int i; - - if ( m_Route[m_iRouteIndex].iType == 0 ) - { - ALERT( at_aiconsole, "Can't draw route!\n" ); - return; - } - -// UTIL_ParticleEffect ( m_Route[ m_iRouteIndex ].vecLocation, g_vecZero, 255, 25 ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.x ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.y ); - WRITE_COORD( m_Route[ m_iRouteIndex ].vecLocation.z ); - - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 16 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( r ); // r, g, b - WRITE_BYTE( g ); // r, g, b - WRITE_BYTE( b ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - for ( i = m_iRouteIndex ; i < ROUTE_SIZE - 1; i++ ) - { - if ( (m_Route[ i ].iType & bits_MF_IS_GOAL) || (m_Route[ i+1 ].iType == 0) ) - break; - - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD( m_Route[ i ].vecLocation.x ); - WRITE_COORD( m_Route[ i ].vecLocation.y ); - WRITE_COORD( m_Route[ i ].vecLocation.z ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.x ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.y ); - WRITE_COORD( m_Route[ i + 1 ].vecLocation.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 8 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( r ); // r, g, b - WRITE_BYTE( g ); // r, g, b - WRITE_BYTE( b ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - -// UTIL_ParticleEffect ( m_Route[ i ].vecLocation, g_vecZero, 255, 25 ); - } -} -#endif - - -int ShouldSimplify( int routeType ) -{ - routeType &= ~bits_MF_IS_GOAL; - - if ( (routeType == bits_MF_TO_PATHCORNER) || (routeType & bits_MF_DONT_SIMPLIFY) ) - return FALSE; - return TRUE; -} - -//========================================================= -// RouteSimplify -// -// Attempts to make the route more direct by cutting out -// unnecessary nodes & cutting corners. -// -//========================================================= -void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) -{ - // BUGBUG: this doesn't work 100% yet - int i, count, outCount; - Vector vecStart; - WayPoint_t outRoute[ ROUTE_SIZE * 2 ]; // Any points except the ends can turn into 2 points in the simplified route - - count = 0; - - for ( i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) - { - if ( !m_Route[i].iType ) - break; - else - count++; - if ( m_Route[i].iType & bits_MF_IS_GOAL ) - break; - } - // Can't simplify a direct route! - if ( count < 2 ) - { -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 0, 255 ); - return; - } - - outCount = 0; - vecStart = pev->origin; - for ( i = 0; i < count-1; i++ ) - { - // Don't eliminate path_corners - if ( !ShouldSimplify( m_Route[m_iRouteIndex+i].iType ) ) - { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - outCount++; - } - else if ( CheckLocalMove ( vecStart, m_Route[m_iRouteIndex+i+1].vecLocation, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - // Skip vert - continue; - } - else - { - Vector vecTest, vecSplit; - - // Halfway between this and next - vecTest = (m_Route[m_iRouteIndex+i+1].vecLocation + m_Route[m_iRouteIndex+i].vecLocation) * 0.5; - - // Halfway between this and previous - vecSplit = (m_Route[m_iRouteIndex+i].vecLocation + vecStart) * 0.5; - - int iType = (m_Route[m_iRouteIndex+i].iType | bits_MF_TO_DETOUR) & ~bits_MF_NOT_TO_MASK; - if ( CheckLocalMove ( vecStart, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - outRoute[outCount].iType = iType; - outRoute[outCount].vecLocation = vecTest; - } - else if ( CheckLocalMove ( vecSplit, vecTest, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - outRoute[outCount].iType = iType; - outRoute[outCount].vecLocation = vecSplit; - outRoute[outCount+1].iType = iType; - outRoute[outCount+1].vecLocation = vecTest; - outCount++; // Adding an extra point - } - else - { - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - } - } - // Get last point - vecStart = outRoute[ outCount ].vecLocation; - outCount++; - } - ASSERT( i < count ); - outRoute[outCount] = m_Route[ m_iRouteIndex + i ]; - outCount++; - - // Terminate - outRoute[outCount].iType = 0; - ASSERT( outCount < (ROUTE_SIZE*2) ); - -// Copy the simplified route, disable for testing - m_iRouteIndex = 0; - for ( i = 0; i < ROUTE_SIZE && i < outCount; i++ ) - { - m_Route[i] = outRoute[i]; - } - - // Terminate route - if ( i < ROUTE_SIZE ) - m_Route[i].iType = 0; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT( "simplify" ) != 0 ) - DrawRoute( pev, outRoute, 0, 255, 0, 0 ); -// else - DrawRoute( pev, m_Route, m_iRouteIndex, 0, 255, 0 ); -#endif -} - -//========================================================= -// FBecomeProne - tries to send a monster into PRONE state. -// right now only used when a barnacle snatches someone, so -// may have some special case stuff for that. -//========================================================= -BOOL CBaseMonster :: FBecomeProne ( void ) -{ - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - pev->flags -= FL_ONGROUND; - } - - m_IdealMonsterState = MONSTERSTATE_PRONE; - return TRUE; -} - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDist > 64 && flDist <= 784 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 -//========================================================= -BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if ( flDist > 64 && flDist <= 512 && flDot >= 0.5 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - // Decent fix to keep folks from kicking/punching hornets and snarks is to check the onground flag(sjb) - if ( flDist <= 64 && flDot >= 0.7 && m_hEnemy != 0 && FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 -//========================================================= -BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) -{ - if ( flDist <= 64 && flDot >= 0.7 ) - { - return TRUE; - } - return FALSE; -} - -//========================================================= -// CheckAttacks - sets all of the bits for attacks that the -// monster is capable of carrying out on the passed entity. -//========================================================= -void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) -{ - Vector2D vec2LOS; - float flDot; - - UTIL_MakeVectors ( pev->angles ); - - vec2LOS = ( pTarget->pev->origin - pev->origin ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - flDot = DotProduct (vec2LOS , gpGlobals->v_forward.Make2D() ); - - // we know the enemy is in front now. We'll find which attacks the monster is capable of by - // checking for corresponding Activities in the model file, then do the simple checks to validate - // those attack types. - - // Clear all attack conditions - ClearConditions( bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK1 |bits_COND_CAN_MELEE_ATTACK2 ); - - if ( m_afCapability & bits_CAP_RANGE_ATTACK1 ) - { - if ( CheckRangeAttack1 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_RANGE_ATTACK1 ); - } - if ( m_afCapability & bits_CAP_RANGE_ATTACK2 ) - { - if ( CheckRangeAttack2 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_RANGE_ATTACK2 ); - } - if ( m_afCapability & bits_CAP_MELEE_ATTACK1 ) - { - if ( CheckMeleeAttack1 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_MELEE_ATTACK1 ); - } - if ( m_afCapability & bits_CAP_MELEE_ATTACK2 ) - { - if ( CheckMeleeAttack2 ( flDot, flDist ) ) - SetConditions( bits_COND_CAN_MELEE_ATTACK2 ); - } -} - -//========================================================= -// CanCheckAttacks - prequalifies a monster to do more fine -// checking of potential attacks. -//========================================================= -BOOL CBaseMonster :: FCanCheckAttacks ( void ) -{ - if ( HasConditions(bits_COND_SEE_ENEMY) && !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckEnemy - part of the Condition collection process, -// gets and stores data and conditions pertaining to a monster's -// enemy. Returns TRUE if Enemy LKP was updated. -//========================================================= -int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) -{ - float flDistToEnemy; - int iUpdatedLKP;// set this to TRUE if you update the EnemyLKP in this function. - - iUpdatedLKP = FALSE; - ClearConditions ( bits_COND_ENEMY_FACING_ME ); - - if ( !FVisible( pEnemy ) ) - { - ASSERT(!HasConditions(bits_COND_SEE_ENEMY)); - SetConditions( bits_COND_ENEMY_OCCLUDED ); - } - else - ClearConditions( bits_COND_ENEMY_OCCLUDED ); - - if ( !pEnemy->IsAlive() ) - { - SetConditions ( bits_COND_ENEMY_DEAD ); - ClearConditions( bits_COND_SEE_ENEMY | bits_COND_ENEMY_OCCLUDED ); - return FALSE; - } - - Vector vecEnemyPos = pEnemy->pev->origin; - // distance to enemy's origin - flDistToEnemy = ( vecEnemyPos - pev->origin ).Length(); - vecEnemyPos.z += pEnemy->pev->size.z * 0.5; - // distance to enemy's head - float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); - if (flDistToEnemy2 < flDistToEnemy) - flDistToEnemy = flDistToEnemy2; - else - { - // distance to enemy's feet - vecEnemyPos.z -= pEnemy->pev->size.z; - float flDistToEnemy2 = (vecEnemyPos - pev->origin).Length(); - if (flDistToEnemy2 < flDistToEnemy) - flDistToEnemy = flDistToEnemy2; - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - { - CBaseMonster *pEnemyMonster; - - iUpdatedLKP = TRUE; - m_vecEnemyLKP = pEnemy->pev->origin; - - pEnemyMonster = pEnemy->MyMonsterPointer(); - - if ( pEnemyMonster ) - { - if ( pEnemyMonster->FInViewCone ( this ) ) - { - SetConditions ( bits_COND_ENEMY_FACING_ME ); - } - else - ClearConditions( bits_COND_ENEMY_FACING_ME ); - } - - if (pEnemy->pev->velocity != Vector( 0, 0, 0)) - { - // trail the enemy a bit - m_vecEnemyLKP = m_vecEnemyLKP - pEnemy->pev->velocity * RANDOM_FLOAT( -0.05, 0 ); - } - else - { - // UNDONE: use pev->oldorigin? - } - } - else if ( !HasConditions(bits_COND_ENEMY_OCCLUDED|bits_COND_SEE_ENEMY) && ( flDistToEnemy <= 256 ) ) - { - // if the enemy is not occluded, and unseen, that means it is behind or beside the monster. - // if the enemy is near enough the monster, we go ahead and let the monster know where the - // enemy is. - iUpdatedLKP = TRUE; - m_vecEnemyLKP = pEnemy->pev->origin; - } - - if ( flDistToEnemy >= m_flDistTooFar ) - { - // enemy is very far away from monster - SetConditions( bits_COND_ENEMY_TOOFAR ); - } - else - ClearConditions( bits_COND_ENEMY_TOOFAR ); - - if ( FCanCheckAttacks() ) - { - CheckAttacks ( m_hEnemy, flDistToEnemy ); - } - - if ( m_movementGoal == MOVEGOAL_ENEMY ) - { - for ( int i = m_iRouteIndex; i < ROUTE_SIZE; i++ ) - { - if ( m_Route[ i ].iType == (bits_MF_IS_GOAL|bits_MF_TO_ENEMY) ) - { - // UNDONE: Should we allow monsters to override this distance (80?) - if ( (m_Route[ i ].vecLocation - m_vecEnemyLKP).Length() > 80 ) - { - // Refresh - FRefreshRoute(); - return iUpdatedLKP; - } - } - } - } - - return iUpdatedLKP; -} - -//========================================================= -// PushEnemy - remember the last few enemies, always remember the player -//========================================================= -void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) -{ - int i; - - if (pEnemy == NULL) - return; - - // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. - for (i = 0; i < MAX_OLD_ENEMIES; i++) - { - if (m_hOldEnemy[i] == pEnemy) - return; - if (m_hOldEnemy[i] == 0) // someone died, reuse their slot - break; - } - if (i >= MAX_OLD_ENEMIES) - return; - - m_hOldEnemy[i] = pEnemy; - m_vecOldEnemy[i] = vecLastKnownPos; -} - -//========================================================= -// PopEnemy - try remembering the last few enemies -//========================================================= -BOOL CBaseMonster :: PopEnemy( ) -{ - // UNDONE: blah, this is bad, we should use a stack but I'm too lazy to code one. - for (int i = MAX_OLD_ENEMIES - 1; i >= 0; i--) - { - if (m_hOldEnemy[i] != 0) - { - if (m_hOldEnemy[i]->IsAlive( )) // cheat and know when they die - { - m_hEnemy = m_hOldEnemy[i]; - m_vecEnemyLKP = m_vecOldEnemy[i]; - // ALERT( at_console, "remembering\n"); - return TRUE; - } - else - { - m_hOldEnemy[i] = NULL; - } - } - } - return FALSE; -} - -//========================================================= -// SetActivity -//========================================================= -void CBaseMonster :: SetActivity ( Activity NewActivity ) -{ - int iSequence; - - iSequence = LookupActivity ( NewActivity ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - // don't reset frame between walk and run - if ( !(m_Activity == ACT_WALK || m_Activity == ACT_RUN) || !(NewActivity == ACT_WALK || NewActivity == ACT_RUN)) - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_aiconsole, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // In case someone calls this with something other than the ideal activity - m_IdealActivity = m_Activity; - - -} - -//========================================================= -// SetSequenceByName -//========================================================= -void CBaseMonster :: SetSequenceByName ( const char *szSequence ) -{ - int iSequence; - - iSequence = LookupSequence ( szSequence ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_aiconsole, "%s has no sequence named:%f\n", STRING(pev->classname), szSequence ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// CheckLocalMove - returns TRUE if the caller can walk a -// straight line from its current origin to the given -// location. If so, don't use the node graph! -// -// if a valid pointer to a int is passed, the function -// will fill that int with the distance that the check -// reached before hitting something. THIS ONLY HAPPENS -// IF THE LOCAL MOVE CHECK FAILS! -// -// !!!PERFORMANCE - should we try to load balance this? -// DON"T USE SETORIGIN! -//========================================================= -#define LOCAL_STEP_SIZE 16 -int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) -{ - Vector vecStartPos;// record monster's position before trying the move - float flYaw; - float flDist; - float flStep, stepSize; - int iReturn; - - vecStartPos = pev->origin; - - - flYaw = UTIL_VecToYaw ( vecEnd - vecStart );// build a yaw that points to the goal. - flDist = ( vecEnd - vecStart ).Length2D();// get the distance. - iReturn = LOCALMOVE_VALID;// assume everything will be ok. - - // move the monster to the start of the local move that's to be checked. - UTIL_SetOrigin( pev, vecStart );// !!!BUGBUG - won't this fire triggers? - nope, SetOrigin doesn't fire - - if ( !(pev->flags & (FL_FLY|FL_SWIM)) ) - { - DROP_TO_FLOOR( ENT( pev ) );//make sure monster is on the floor! - } - - //pev->origin.z = vecStartPos.z;//!!!HACKHACK - -// pev->origin = vecStart; - -/* - if ( flDist > 1024 ) - { - // !!!PERFORMANCE - this operation may be too CPU intensive to try checks this large. - // We don't lose much here, because a distance this great is very likely - // to have something in the way. - - // since we've actually moved the monster during the check, undo the move. - pev->origin = vecStartPos; - return FALSE; - } -*/ - // this loop takes single steps to the goal. - for ( flStep = 0 ; flStep < flDist ; flStep += LOCAL_STEP_SIZE ) - { - stepSize = LOCAL_STEP_SIZE; - - if ( (flStep + LOCAL_STEP_SIZE) >= (flDist-1) ) - stepSize = (flDist - flStep) - 1; - -// UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); - - if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, WALKMOVE_CHECKONLY ) ) - {// can't take the next step, fail! - - if ( pflDist != NULL ) - { - *pflDist = flStep; - } - if ( pTarget && pTarget->edict() == gpGlobals->trace_ent ) - { - // if this step hits target ent, the move is legal. - iReturn = LOCALMOVE_VALID; - break; - } - else - { - // If we're going toward an entity, and we're almost getting there, it's OK. -// if ( pTarget && fabs( flDist - iStep ) < LOCAL_STEP_SIZE ) -// fReturn = TRUE; -// else - iReturn = LOCALMOVE_INVALID; - break; - } - - } - } - - if ( iReturn == LOCALMOVE_VALID && !(pev->flags & (FL_FLY|FL_SWIM) ) && (!pTarget || (pTarget->pev->flags & FL_ONGROUND)) ) - { - // The monster can move to a spot UNDER the target, but not to it. Don't try to triangulate, go directly to the node graph. - // UNDONE: Magic # 64 -- this used to be pev->size.z but that won't work for small creatures like the headcrab - if ( fabs(vecEnd.z - pev->origin.z) > 64 ) - { - iReturn = LOCALMOVE_INVALID_DONT_TRIANGULATE; - } - } - /* - // uncommenting this block will draw a line representing the nearest legal move. - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - WRITE_COORD(MSG_BROADCAST, pev->origin.x); - WRITE_COORD(MSG_BROADCAST, pev->origin.y); - WRITE_COORD(MSG_BROADCAST, pev->origin.z); - WRITE_COORD(MSG_BROADCAST, vecStart.x); - WRITE_COORD(MSG_BROADCAST, vecStart.y); - WRITE_COORD(MSG_BROADCAST, vecStart.z); - */ - - // since we've actually moved the monster during the check, undo the move. - UTIL_SetOrigin( pev, vecStartPos ); - - return iReturn; -} - - -float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) -{ - float flTravelTime = 0; - - //ALERT(at_aiconsole, "A door. "); - CBaseEntity *pcbeDoor = CBaseEntity::Instance(pevDoor); - if (pcbeDoor && !pcbeDoor->IsLockedByMaster()) - { - //ALERT(at_aiconsole, "unlocked! "); - pcbeDoor->Use(this, this, USE_ON, 0.0); - //ALERT(at_aiconsole, "pevDoor->nextthink = %d ms\n", (int)(1000*pevDoor->nextthink)); - //ALERT(at_aiconsole, "pevDoor->ltime = %d ms\n", (int)(1000*pevDoor->ltime)); - //ALERT(at_aiconsole, "pev-> nextthink = %d ms\n", (int)(1000*pev->nextthink)); - //ALERT(at_aiconsole, "pev->ltime = %d ms\n", (int)(1000*pev->ltime)); - flTravelTime = pevDoor->nextthink - pevDoor->ltime; - //ALERT(at_aiconsole, "Waiting %d ms\n", (int)(1000*flTravelTime)); - if ( pcbeDoor->pev->targetname ) - { - edict_t *pentTarget = NULL; - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pcbeDoor->pev->targetname)); - - if ( VARS( pentTarget ) != pcbeDoor->pev ) - { - if (FNullEnt(pentTarget)) - break; - - if ( FClassnameIs ( pentTarget, STRING(pcbeDoor->pev->classname) ) ) - { - CBaseEntity *pDoor = Instance(pentTarget); - if ( pDoor ) - pDoor->Use(this, this, USE_ON, 0.0); - } - } - } - } - } - - return gpGlobals->time + flTravelTime; -} - - -//========================================================= -// AdvanceRoute - poorly named function that advances the -// m_iRouteIndex. If it goes beyond ROUTE_SIZE, the route -// is refreshed. -//========================================================= -void CBaseMonster :: AdvanceRoute ( float distance ) -{ - - if ( m_iRouteIndex == ROUTE_SIZE - 1 ) - { - // time to refresh the route. - if ( !FRefreshRoute() ) - { - ALERT ( at_aiconsole, "Can't Refresh Route!!\n" ); - } - } - else - { - if ( ! (m_Route[ m_iRouteIndex ].iType & bits_MF_IS_GOAL) ) - { - // If we've just passed a path_corner, advance m_pGoalEnt - if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_PATHCORNER ) - m_pGoalEnt = m_pGoalEnt->GetNextTarget(); - - // IF both waypoints are nodes, then check for a link for a door and operate it. - // - if ( (m_Route[m_iRouteIndex].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE - && (m_Route[m_iRouteIndex+1].iType & bits_MF_TO_NODE) == bits_MF_TO_NODE) - { - //ALERT(at_aiconsole, "SVD: Two nodes. "); - - int iSrcNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex].vecLocation, this ); - int iDestNode = WorldGraph.FindNearestNode(m_Route[m_iRouteIndex+1].vecLocation, this ); - - int iLink; - WorldGraph.HashSearch(iSrcNode, iDestNode, iLink); - - if ( iLink >= 0 && WorldGraph.m_pLinkPool[iLink].m_pLinkEnt != NULL ) - { - //ALERT(at_aiconsole, "A link. "); - if ( WorldGraph.HandleLinkEnt ( iSrcNode, WorldGraph.m_pLinkPool[iLink].m_pLinkEnt, m_afCapability, CGraph::NODEGRAPH_DYNAMIC ) ) - { - //ALERT(at_aiconsole, "usable."); - entvars_t *pevDoor = WorldGraph.m_pLinkPool[iLink].m_pLinkEnt; - if (pevDoor) - { - m_flMoveWaitFinished = OpenDoorAndWait( pevDoor ); -// ALERT( at_aiconsole, "Wating for door %.2f\n", m_flMoveWaitFinished-gpGlobals->time ); - } - } - } - //ALERT(at_aiconsole, "\n"); - } - m_iRouteIndex++; - } - else // At goal!!! - { - if ( distance < m_flGroundSpeed * 0.2 /* FIX */ ) - { - MovementComplete(); - } - } - } -} - - -int CBaseMonster :: RouteClassify( int iMoveFlag ) -{ - int movementGoal; - - movementGoal = MOVEGOAL_NONE; - - if ( iMoveFlag & bits_MF_TO_TARGETENT ) - movementGoal = MOVEGOAL_TARGETENT; - else if ( iMoveFlag & bits_MF_TO_ENEMY ) - movementGoal = MOVEGOAL_ENEMY; - else if ( iMoveFlag & bits_MF_TO_PATHCORNER ) - movementGoal = MOVEGOAL_PATHCORNER; - else if ( iMoveFlag & bits_MF_TO_NODE ) - movementGoal = MOVEGOAL_NODE; - else if ( iMoveFlag & bits_MF_TO_LOCATION ) - movementGoal = MOVEGOAL_LOCATION; - - return movementGoal; -} - -//========================================================= -// BuildRoute -//========================================================= -BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) -{ - float flDist; - Vector vecApex; - int iLocalMove; - - RouteNew(); - m_movementGoal = RouteClassify( iMoveFlag ); - -// so we don't end up with no moveflags - m_Route[ 0 ].vecLocation = vecGoal; - m_Route[ 0 ].iType = iMoveFlag | bits_MF_IS_GOAL; - -// check simple local move - iLocalMove = CheckLocalMove( pev->origin, vecGoal, pTarget, &flDist ); - - if ( iLocalMove == LOCALMOVE_VALID ) - { - // monster can walk straight there! - return TRUE; - } -// try to triangulate around any obstacles. - else if ( iLocalMove != LOCALMOVE_INVALID_DONT_TRIANGULATE && FTriangulate( pev->origin, vecGoal, flDist, pTarget, &vecApex ) ) - { - // there is a slightly more complicated path that allows the monster to reach vecGoal - m_Route[ 0 ].vecLocation = vecApex; - m_Route[ 0 ].iType = (iMoveFlag | bits_MF_TO_DETOUR); - - m_Route[ 1 ].vecLocation = vecGoal; - m_Route[ 1 ].iType = iMoveFlag | bits_MF_IS_GOAL; - - /* - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - WRITE_COORD(MSG_BROADCAST, vecApex.x ); - WRITE_COORD(MSG_BROADCAST, vecApex.y ); - WRITE_COORD(MSG_BROADCAST, vecApex.z ); - WRITE_COORD(MSG_BROADCAST, vecApex.x ); - WRITE_COORD(MSG_BROADCAST, vecApex.y ); - WRITE_COORD(MSG_BROADCAST, vecApex.z + 128 ); - */ - - RouteSimplify( pTarget ); - return TRUE; - } - -// last ditch, try nodes - if ( FGetNodeRoute( vecGoal ) ) - { -// ALERT ( at_console, "Can get there on nodes\n" ); - m_vecMoveGoal = vecGoal; - RouteSimplify( pTarget ); - return TRUE; - } - - // b0rk - return FALSE; -} - - -//========================================================= -// InsertWaypoint - Rebuilds the existing route so that the -// supplied vector and moveflags are the first waypoint in -// the route, and fills the rest of the route with as much -// of the pre-existing route as possible -//========================================================= -void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) -{ - int i, type; - - - // we have to save some Index and Type information from the real - // path_corner or node waypoint that the monster was trying to reach. This makes sure that data necessary - // to refresh the original path exists even in the new waypoints that don't correspond directy to a path_corner - // or node. - type = afMoveFlags | (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK); - - for ( i = ROUTE_SIZE-1; i > 0; i-- ) - m_Route[i] = m_Route[i-1]; - - m_Route[ m_iRouteIndex ].vecLocation = vecLocation; - m_Route[ m_iRouteIndex ].iType = type; -} - -//========================================================= -// FTriangulate - tries to overcome local obstacles by -// triangulating a path around them. -// -// iApexDist is how far the obstruction that we are trying -// to triangulate around is from the monster. -//========================================================= -BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) -{ - Vector vecDir; - Vector vecForward; - Vector vecLeft;// the spot we'll try to triangulate to on the left - Vector vecRight;// the spot we'll try to triangulate to on the right - Vector vecTop;// the spot we'll try to triangulate to on the top - Vector vecBottom;// the spot we'll try to triangulate to on the bottom - Vector vecFarSide;// the spot that we'll move to after hitting the triangulated point, before moving on to our normal goal. - int i; - float sizeX, sizeZ; - - // If the hull width is less than 24, use 24 because CheckLocalMove uses a min of - // 24. - sizeX = pev->size.x; - if (sizeX < 24.0) - sizeX = 24.0; - else if (sizeX > 48.0) - sizeX = 48.0; - sizeZ = pev->size.z; - //if (sizeZ < 24.0) - // sizeZ = 24.0; - - vecForward = ( vecEnd - vecStart ).Normalize(); - - Vector vecDirUp(0,0,1); - vecDir = CrossProduct ( vecForward, vecDirUp); - - // start checking right about where the object is, picking two equidistant starting points, one on - // the left, one on the right. As we progress through the loop, we'll push these away from the obstacle, - // hoping to find a way around on either side. pev->size.x is added to the ApexDist in order to help select - // an apex point that insures that the monster is sufficiently past the obstacle before trying to turn back - // onto its original course. - - vecLeft = pev->origin + ( vecForward * ( flDist + sizeX ) ) - vecDir * ( sizeX * 3 ); - vecRight = pev->origin + ( vecForward * ( flDist + sizeX ) ) + vecDir * ( sizeX * 3 ); - if (pev->movetype == MOVETYPE_FLY) - { - vecTop = pev->origin + (vecForward * flDist) + (vecDirUp * sizeZ * 3); - vecBottom = pev->origin + (vecForward * flDist) - (vecDirUp * sizeZ * 3); - } - - vecFarSide = m_Route[ m_iRouteIndex ].vecLocation; - - vecDir = vecDir * sizeX * 2; - if (pev->movetype == MOVETYPE_FLY) - vecDirUp = vecDirUp * sizeZ * 2; - - for ( i = 0 ; i < 8; i++ ) - { -// Debug, Draw the triangulation -#if 0 - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecRight.x ); - WRITE_COORD( vecRight.y ); - WRITE_COORD( vecRight.z ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecLeft.x ); - WRITE_COORD( vecLeft.y ); - WRITE_COORD( vecLeft.z ); - MESSAGE_END(); -#endif - -#if 0 - if (pev->movetype == MOVETYPE_FLY) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecTop.x ); - WRITE_COORD( vecTop.y ); - WRITE_COORD( vecTop.z ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( vecBottom.x ); - WRITE_COORD( vecBottom.y ); - WRITE_COORD( vecBottom.z ); - MESSAGE_END(); - } -#endif - - if ( CheckLocalMove( pev->origin, vecRight, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecRight, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecRight; - } - - return TRUE; - } - } - if ( CheckLocalMove( pev->origin, vecLeft, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecLeft, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecLeft; - } - - return TRUE; - } - } - - if (pev->movetype == MOVETYPE_FLY) - { - if ( CheckLocalMove( pev->origin, vecTop, pTargetEnt, NULL ) == LOCALMOVE_VALID) - { - if ( CheckLocalMove ( vecTop, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecTop; - //ALERT(at_aiconsole, "triangulate over\n"); - } - - return TRUE; - } - } -#if 1 - if ( CheckLocalMove( pev->origin, vecBottom, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( CheckLocalMove ( vecBottom, vecFarSide, pTargetEnt, NULL ) == LOCALMOVE_VALID ) - { - if ( pApex ) - { - *pApex = vecBottom; - //ALERT(at_aiconsole, "triangulate under\n"); - } - - return TRUE; - } - } -#endif - } - - vecRight = vecRight + vecDir; - vecLeft = vecLeft - vecDir; - if (pev->movetype == MOVETYPE_FLY) - { - vecTop = vecTop + vecDirUp; - vecBottom = vecBottom - vecDirUp; - } - } - - return FALSE; -} - -//========================================================= -// Move - take a single step towards the next ROUTE location -//========================================================= -#define DIST_TO_CHECK 200 - -void CBaseMonster :: Move ( float flInterval ) -{ - float flWaypointDist; - float flCheckDist; - float flDist;// how far the lookahead check got before hitting an object. - Vector vecDir; - Vector vecApex; - CBaseEntity *pTargetEnt; - - // Don't move if no valid route - if ( FRouteClear() ) - { - // If we still have a movement goal, then this is probably a route truncated by SimplifyRoute() - // so refresh it. - if ( m_movementGoal == MOVEGOAL_NONE || !FRefreshRoute() ) - { - ALERT( at_aiconsole, "Tried to move with no route!\n" ); - TaskFail(); - return; - } - } - - if ( m_flMoveWaitFinished > gpGlobals->time ) - return; - -// Debug, test movement code -#if 0 -// if ( CVAR_GET_FLOAT("stopmove" ) != 0 ) - { - if ( m_movementGoal == MOVEGOAL_ENEMY ) - RouteSimplify( m_hEnemy ); - else - RouteSimplify( m_hTargetEnt ); - FRefreshRoute(); - return; - } -#else -// Debug, draw the route -// DrawRoute( pev, m_Route, m_iRouteIndex, 0, 200, 0 ); -#endif - - // if the monster is moving directly towards an entity (enemy for instance), we'll set this pointer - // to that entity for the CheckLocalMove and Triangulate functions. - pTargetEnt = NULL; - - // local move to waypoint. - vecDir = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Normalize(); - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); - - MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - ChangeYaw ( pev->yaw_speed ); - - // if the waypoint is closer than CheckDist, CheckDist is the dist to waypoint - if ( flWaypointDist < DIST_TO_CHECK ) - { - flCheckDist = flWaypointDist; - } - else - { - flCheckDist = DIST_TO_CHECK; - } - - if ( (m_Route[ m_iRouteIndex ].iType & (~bits_MF_NOT_TO_MASK)) == bits_MF_TO_ENEMY ) - { - // only on a PURE move to enemy ( i.e., ONLY MF_TO_ENEMY set, not MF_TO_ENEMY and DETOUR ) - pTargetEnt = m_hEnemy; - } - else if ( (m_Route[ m_iRouteIndex ].iType & ~bits_MF_NOT_TO_MASK) == bits_MF_TO_TARGETENT ) - { - pTargetEnt = m_hTargetEnt; - } - - // !!!BUGBUG - CheckDist should be derived from ground speed. - // If this fails, it should be because of some dynamic entity blocking this guy. - // We've already checked this path, so we should wait and time out if the entity doesn't move - flDist = 0; - if ( CheckLocalMove ( pev->origin, pev->origin + vecDir * flCheckDist, pTargetEnt, &flDist ) != LOCALMOVE_VALID ) - { - CBaseEntity *pBlocker; - - // Can't move, stop - Stop(); - // Blocking entity is in global trace_ent - pBlocker = CBaseEntity::Instance( gpGlobals->trace_ent ); - if (pBlocker) - { - DispatchBlocked( edict(), pBlocker->edict() ); - } - - if ( pBlocker && m_moveWaitTime > 0 && pBlocker->IsMoving() && !pBlocker->IsPlayer() && (gpGlobals->time-m_flMoveWaitFinished) > 3.0 ) - { - // Can we still move toward our target? - if ( flDist < m_flGroundSpeed ) - { - // No, Wait for a second - m_flMoveWaitFinished = gpGlobals->time + m_moveWaitTime; - return; - } - // Ok, still enough room to take a step - } - else - { - // try to triangulate around whatever is in the way. - if ( FTriangulate( pev->origin, m_Route[ m_iRouteIndex ].vecLocation, flDist, pTargetEnt, &vecApex ) ) - { - InsertWaypoint( vecApex, bits_MF_TO_DETOUR ); - RouteSimplify( pTargetEnt ); - } - else - { -// ALERT ( at_aiconsole, "Couldn't Triangulate\n" ); - Stop(); - // Only do this once until your route is cleared - if ( m_moveWaitTime > 0 && !(m_afMemory & bits_MEMORY_MOVE_FAILED) ) - { - FRefreshRoute(); - if ( FRouteClear() ) - { - TaskFail(); - } - else - { - // Don't get stuck - if ( (gpGlobals->time - m_flMoveWaitFinished) < 0.2 ) - Remember( bits_MEMORY_MOVE_FAILED ); - - m_flMoveWaitFinished = gpGlobals->time + 0.1; - } - } - else - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to move (%d)!\n", STRING(pev->classname), HasMemory( bits_MEMORY_MOVE_FAILED ) ); - //ALERT( at_aiconsole, "%f, %f, %f\n", pev->origin.z, (pev->origin + (vecDir * flCheckDist)).z, m_Route[m_iRouteIndex].vecLocation.z ); - } - return; - } - } - } - - // close enough to the target, now advance to the next target. This is done before actually reaching - // the target so that we get a nice natural turn while moving. - if ( ShouldAdvanceRoute( flWaypointDist ) )///!!!BUGBUG- magic number - { - AdvanceRoute( flWaypointDist ); - } - - // Might be waiting for a door - if ( m_flMoveWaitFinished > gpGlobals->time ) - { - Stop(); - return; - } - - // UNDONE: this is a hack to quit moving farther than it has looked ahead. - if (flCheckDist < m_flGroundSpeed * flInterval) - { - flInterval = flCheckDist / m_flGroundSpeed; - // ALERT( at_console, "%.02f\n", flInterval ); - } - MoveExecute( pTargetEnt, vecDir, flInterval ); - - if ( MovementIsComplete() ) - { - Stop(); - RouteClear(); - } -} - - -BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) -{ - if ( flWaypointDist <= MONSTER_CUT_CORNER_DIST ) - { - // ALERT( at_console, "cut %f\n", flWaypointDist ); - return TRUE; - } - - return FALSE; -} - - -void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ -// float flYaw = UTIL_VecToYaw ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin );// build a yaw that points to the goal. -// WALK_MOVE( ENT(pev), flYaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); - if ( m_IdealActivity != m_movementActivity ) - m_IdealActivity = m_movementActivity; - - float flTotal = m_flGroundSpeed * pev->framerate * flInterval; - float flStep; - while (flTotal > 0.001) - { - // don't walk more than 16 units or stairs stop working - flStep = min( 16.0, flTotal ); - UTIL_MoveToOrigin ( ENT(pev), m_Route[ m_iRouteIndex ].vecLocation, flStep, MOVE_NORMAL ); - flTotal -= flStep; - } - // ALERT( at_console, "dist %f\n", m_flGroundSpeed * pev->framerate * flInterval ); -} - - -//========================================================= -// MonsterInit - after a monster is spawned, it needs to -// be dropped into the world, checked for mobility problems, -// and put on the proper path, if any. This function does -// all of those things after the monster spawns. Any -// initialization that should take place for all monsters -// goes here. -//========================================================= -void CBaseMonster :: MonsterInit ( void ) -{ - if (!g_pGameRules->FAllowMonsters()) - { - pev->flags |= FL_KILLME; // Post this because some monster code modifies class data after calling this function -// REMOVE_ENTITY(ENT(pev)); - return; - } - - // Set fields common to all monsters - pev->effects = 0; - pev->takedamage = DAMAGE_AIM; - pev->ideal_yaw = pev->angles.y; - pev->max_health = pev->health; - pev->deadflag = DEAD_NO; - m_IdealMonsterState = MONSTERSTATE_IDLE;// Assume monster will be idle, until proven otherwise - - m_IdealActivity = ACT_IDLE; - - SetBits (pev->flags, FL_MONSTER); - if ( pev->spawnflags & SF_MONSTER_HITMONSTERCLIP ) - pev->flags |= FL_MONSTERCLIP; - - ClearSchedule(); - RouteClear(); - InitBoneControllers( ); // FIX: should be done in Spawn - - m_iHintNode = NO_NODE; - - m_afMemory = MEMORY_CLEAR; - - m_hEnemy = NULL; - - m_flDistTooFar = 1024.0; - m_flDistLook = 2048.0; - - // set eye position - SetEyePosition(); - - SetThink( &CBaseMonster::MonsterInitThink ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse ( &CBaseMonster::MonsterUse ); -} - -//========================================================= -// MonsterInitThink - Calls StartMonster. Startmonster is -// virtual, but this function cannot be -//========================================================= -void CBaseMonster :: MonsterInitThink ( void ) -{ - StartMonster(); -} - -//========================================================= -// StartMonster - final bit of initization before a monster -// is turned over to the AI. -//========================================================= -void CBaseMonster :: StartMonster ( void ) -{ - // update capabilities - if ( LookupActivity ( ACT_RANGE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_RANGE_ATTACK1; - } - if ( LookupActivity ( ACT_RANGE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_RANGE_ATTACK2; - } - if ( LookupActivity ( ACT_MELEE_ATTACK1 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_MELEE_ATTACK1; - } - if ( LookupActivity ( ACT_MELEE_ATTACK2 ) != ACTIVITY_NOT_AVAILABLE ) - { - m_afCapability |= bits_CAP_MELEE_ATTACK2; - } - - // Raise monster off the floor one unit, then drop to floor - if ( pev->movetype != MOVETYPE_FLY && !FBitSet( pev->spawnflags, SF_MONSTER_FALL_TO_GROUND ) ) - { - pev->origin.z += 1; - DROP_TO_FLOOR ( ENT(pev) ); - // Try to move the monster to make sure it's not stuck in a brush. - if (!WALK_MOVE ( ENT(pev), 0, 0, WALKMOVE_NORMAL ) ) - { - ALERT(at_error, "Monster %s stuck in wall--level design error", STRING(pev->classname)); - pev->effects = EF_BRIGHTFIELD; - } - } - else - { - pev->flags &= ~FL_ONGROUND; - } - - if ( !FStringNull(pev->target) )// this monster has a target - { - // Find the monster's initial target entity, stash it - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); - - if ( !m_pGoalEnt ) - { - ALERT(at_error, "ReadyMonster()--%s couldn't find target %s", STRING(pev->classname), STRING(pev->target)); - } - else - { - // Monster will start turning towards his destination - MakeIdealYaw ( m_pGoalEnt->pev->origin ); - - // JAY: How important is this error message? Big Momma doesn't obey this rule, so I took it out. -#if 0 - // At this point, we expect only a path_corner as initial goal - if (!FClassnameIs( m_pGoalEnt->pev, "path_corner")) - { - ALERT(at_warning, "ReadyMonster--monster's initial goal '%s' is not a path_corner", STRING(pev->target)); - } -#endif - - // set the monster up to walk a path corner path. - // !!!BUGBUG - this is a minor bit of a hack. - // JAYJAY - m_movementGoal = MOVEGOAL_PATHCORNER; - - if ( pev->movetype == MOVETYPE_FLY ) - m_movementActivity = ACT_FLY; - else - m_movementActivity = ACT_WALK; - - if ( !FRefreshRoute() ) - { - ALERT ( at_aiconsole, "Can't Create Route!\n" ); - } - SetState( MONSTERSTATE_IDLE ); - ChangeSchedule( GetScheduleOfType( SCHED_IDLE_WALK ) ); - } - } - - //SetState ( m_IdealMonsterState ); - //SetActivity ( m_IdealActivity ); - - // Delay drop to floor to make sure each door in the level has had its chance to spawn - // Spread think times so that they don't all happen at the same time (Carmack) - SetThink ( &CBaseMonster::CallMonsterThink ); - pev->nextthink += RANDOM_FLOAT(0.1, 0.4); // spread think times. - - if ( !FStringNull(pev->targetname) )// wait until triggered - { - SetState( MONSTERSTATE_IDLE ); - // UNDONE: Some scripted sequence monsters don't have an idle? - SetActivity( ACT_IDLE ); - ChangeSchedule( GetScheduleOfType( SCHED_WAIT_TRIGGER ) ); - } -} - - -void CBaseMonster :: MovementComplete( void ) -{ - switch( m_iTaskStatus ) - { - case TASKSTATUS_NEW: - case TASKSTATUS_RUNNING: - m_iTaskStatus = TASKSTATUS_RUNNING_TASK; - break; - - case TASKSTATUS_RUNNING_MOVEMENT: - TaskComplete(); - break; - - case TASKSTATUS_RUNNING_TASK: - ALERT( at_error, "Movement completed twice!\n" ); - break; - - case TASKSTATUS_COMPLETE: - break; - } - m_movementGoal = MOVEGOAL_NONE; -} - - -int CBaseMonster::TaskIsRunning( void ) -{ - if ( m_iTaskStatus != TASKSTATUS_COMPLETE && - m_iTaskStatus != TASKSTATUS_RUNNING_MOVEMENT ) - return 1; - - return 0; -} - -//========================================================= -// IRelationship - returns an integer that describes the -// relationship between two types of monster. -//========================================================= -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) -{ - static int iEnemy[14][14] = - { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN - /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, - /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, - /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, - /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, - /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, - /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, - /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, - /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, - /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } - }; - - return iEnemy[ Classify() ][ pTarget->Classify() ]; -} - -//========================================================= -// FindCover - tries to find a nearby node that will hide -// the caller from its enemy. -// -// If supplied, search will return a node at least as far -// away as MinDist, but no farther than MaxDist. -// if MaxDist isn't supplied, it defaults to a reasonable -// value -//========================================================= -// UNDONE: Should this find the nearest node? - -//float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) - -BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) -{ - int i; - int iMyHullIndex; - int iMyNode; - int iThreatNode; - float flDist; - Vector vecLookersOffset; - TraceResult tr; - - if ( !flMaxDist ) - { - // user didn't supply a MaxDist, so work up a crazy one. - flMaxDist = 784; - } - - if ( flMinDist > 0.5 * flMaxDist) - { -#if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); -#endif - flMinDist = 0.5 * flMaxDist; - } - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - { - ALERT ( at_aiconsole, "Graph not ready for findcover!\n" ); - return FALSE; - } - - iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); - iThreatNode = WorldGraph.FindNearestNode ( vecThreat, this ); - iMyHullIndex = WorldGraph.HullIndex( this ); - - if ( iMyNode == NO_NODE ) - { - ALERT ( at_aiconsole, "FindCover() - %s has no nearest node!\n", STRING(pev->classname)); - return FALSE; - } - if ( iThreatNode == NO_NODE ) - { - // ALERT ( at_aiconsole, "FindCover() - Threat has no nearest node!\n" ); - iThreatNode = iMyNode; - // return FALSE; - } - - vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes - - // we'll do a rough sample to find nodes that are relatively nearby - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; - - CNode &node = WorldGraph.Node( nodeNumber ); - WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. - - // could use an optimization here!! - flDist = ( pev->origin - node.m_vecOrigin ).Length(); - - // DON'T do the trace check on a node that is farther away than a node that we've already found to - // provide cover! Also make sure the node is within the mins/maxs of the search. - if ( flDist >= flMinDist && flDist < flMaxDist ) - { - UTIL_TraceLine ( node.m_vecOrigin + vecViewOffset, vecLookersOffset, ignore_monsters, ignore_glass, ENT(pev), &tr ); - - // if this node will block the threat's line of sight to me... - if ( tr.flFraction != 1.0 ) - { - // ..and is also closer to me than the threat, or the same distance from myself and the threat the node is good. - if ( ( iMyNode == iThreatNode ) || WorldGraph.PathLength( iMyNode, nodeNumber, iMyHullIndex, m_afCapability ) <= WorldGraph.PathLength( iThreatNode, nodeNumber, iMyHullIndex, m_afCapability ) ) - { - if ( FValidateCover ( node.m_vecOrigin ) && MoveToLocation( ACT_RUN, 0, node.m_vecOrigin ) ) - { - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( node.m_vecOrigin.x ); - WRITE_COORD( node.m_vecOrigin.y ); - WRITE_COORD( node.m_vecOrigin.z ); - - WRITE_COORD( vecLookersOffset.x ); - WRITE_COORD( vecLookersOffset.y ); - WRITE_COORD( vecLookersOffset.z ); - MESSAGE_END(); - */ - - return TRUE; - } - } - } - } - } - return FALSE; -} - - -//========================================================= -// BuildNearestRoute - tries to build a route as close to the target -// as possible, even if there isn't a path to the final point. -// -// If supplied, search will return a node at least as far -// away as MinDist from vecThreat, but no farther than MaxDist. -// if MaxDist isn't supplied, it defaults to a reasonable -// value -//========================================================= -BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) -{ - int i; - int iMyHullIndex; - int iMyNode; - float flDist; - Vector vecLookersOffset; - TraceResult tr; - - if ( !flMaxDist ) - { - // user didn't supply a MaxDist, so work up a crazy one. - flMaxDist = 784; - } - - if ( flMinDist > 0.5 * flMaxDist) - { -#if _DEBUG - ALERT ( at_console, "FindCover MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist ); -#endif - flMinDist = 0.5 * flMaxDist; - } - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - { - ALERT ( at_aiconsole, "Graph not ready for BuildNearestRoute!\n" ); - return FALSE; - } - - iMyNode = WorldGraph.FindNearestNode( pev->origin, this ); - iMyHullIndex = WorldGraph.HullIndex( this ); - - if ( iMyNode == NO_NODE ) - { - ALERT ( at_aiconsole, "BuildNearestRoute() - %s has no nearest node!\n", STRING(pev->classname)); - return FALSE; - } - - vecLookersOffset = vecThreat + vecViewOffset;// calculate location of enemy's eyes - - // we'll do a rough sample to find nodes that are relatively nearby - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastCoverSearch) % WorldGraph.m_cNodes; - - CNode &node = WorldGraph.Node( nodeNumber ); - WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here. - - // can I get there? - if (WorldGraph.NextNodeInRoute( iMyNode, nodeNumber, iMyHullIndex, 0 ) != iMyNode) - { - flDist = ( vecThreat - node.m_vecOrigin ).Length(); - - // is it close? - if ( flDist > flMinDist && flDist < flMaxDist) - { - // can I see where I want to be from there? - UTIL_TraceLine( node.m_vecOrigin + pev->view_ofs, vecLookersOffset, ignore_monsters, edict(), &tr ); - - if (tr.flFraction == 1.0) - { - // try to actually get there - if ( BuildRoute ( node.m_vecOrigin, bits_MF_TO_LOCATION, NULL ) ) - { - flMaxDist = flDist; - m_vecMoveGoal = node.m_vecOrigin; - return TRUE; // UNDONE: keep looking for something closer! - } - } - } - } - } - - return FALSE; -} - - - -//========================================================= -// BestVisibleEnemy - this functions searches the link -// list whose head is the caller's m_pLink field, and returns -// a pointer to the enemy entity in that list that is nearest the -// caller. -// -// !!!UNDONE - currently, this only returns the closest enemy. -// we'll want to consider distance, relationship, attack types, back turned, etc. -//========================================================= -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) -{ - CBaseEntity *pReturn; - CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; - - iNearest = 8192;// so first visible entity will become the closest. - pNextEnt = m_pLink; - pReturn = NULL; - iBestRelationship = R_NO; - - while ( pNextEnt != NULL ) - { - if ( pNextEnt->IsAlive() ) - { - if ( IRelationship( pNextEnt) > iBestRelationship ) - { - // this entity is disliked MORE than the entity that we - // currently think is the best visible enemy. No need to do - // a distance check, just get mad at this one for now. - iBestRelationship = IRelationship ( pNextEnt ); - iNearest = ( pNextEnt->pev->origin - pev->origin ).Length(); - pReturn = pNextEnt; - } - else if ( IRelationship( pNextEnt) == iBestRelationship ) - { - // this entity is disliked just as much as the entity that - // we currently think is the best visible enemy, so we only - // get mad at it if it is closer. - iDist = ( pNextEnt->pev->origin - pev->origin ).Length(); - - if ( iDist <= iNearest ) - { - iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); - pReturn = pNextEnt; - } - } - } - - pNextEnt = pNextEnt->m_pLink; - } - - return pReturn; -} - - -//========================================================= -// MakeIdealYaw - gets a yaw value for the caller that would -// face the supplied vector. Value is stuffed into the monster's -// ideal_yaw -//========================================================= -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) -{ - Vector vecProjection; - - // strafing monster needs to face 90 degrees away from its goal - if ( m_movementActivity == ACT_STRAFE_LEFT ) - { - vecProjection.x = -vecTarget.y; - vecProjection.y = vecTarget.x; - - pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); - } - else if ( m_movementActivity == ACT_STRAFE_RIGHT ) - { - vecProjection.x = vecTarget.y; - vecProjection.y = vecTarget.x; - - pev->ideal_yaw = UTIL_VecToYaw( vecProjection - pev->origin ); - } - else - { - pev->ideal_yaw = UTIL_VecToYaw ( vecTarget - pev->origin ); - } -} - -//========================================================= -// FlYawDiff - returns the difference ( in degrees ) between -// monster's current yaw and ideal_yaw -// -// Positive result is left turn, negative is right turn -//========================================================= -float CBaseMonster::FlYawDiff ( void ) -{ - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - - if ( flCurrentYaw == pev->ideal_yaw ) - { - return 0; - } - - - return UTIL_AngleDiff( pev->ideal_yaw, flCurrentYaw ); -} - - -//========================================================= -// Changeyaw - turns a monster towards its ideal_yaw -//========================================================= -float CBaseMonster::ChangeYaw ( int yawSpeed ) -{ - float ideal, current, move, speed; - - current = UTIL_AngleMod( pev->angles.y ); - ideal = pev->ideal_yaw; - if (current != ideal) - { - speed = (float)yawSpeed * gpGlobals->frametime * 10; - move = ideal - current; - - if (ideal > current) - { - if (move >= 180) - move = move - 360; - } - else - { - if (move <= -180) - move = move + 360; - } - - if (move > 0) - {// turning to the monster's left - if (move > speed) - move = speed; - } - else - {// turning to the monster's right - if (move < -speed) - move = -speed; - } - - pev->angles.y = UTIL_AngleMod (current + move); - - // turn head in desired direction only if they have a turnable head - if (m_afCapability & bits_CAP_TURN_HEAD) - { - float yaw = pev->ideal_yaw - pev->angles.y; - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - // yaw *= 0.8; - SetBoneController( 0, yaw ); - } - } - else - move = 0; - - return move; -} - -//========================================================= -// VecToYaw - turns a directional vector into a yaw value -// that points down that vector. -//========================================================= -float CBaseMonster::VecToYaw ( Vector vecDir ) -{ - if (vecDir.x == 0 && vecDir.y == 0 && vecDir.z == 0) - return pev->angles.y; - - return UTIL_VecToYaw( vecDir ); -} - - -//========================================================= -// SetEyePosition -// -// queries the monster's model for $eyeposition and copies -// that vector to the monster's view_ofs -// -//========================================================= -void CBaseMonster :: SetEyePosition ( void ) -{ - Vector vecEyePosition; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - GetEyePosition( pmodel, vecEyePosition ); - - pev->view_ofs = vecEyePosition; - - if ( pev->view_ofs == g_vecZero ) - { - ALERT ( at_aiconsole, "%s has no view_ofs!\n", STRING ( pev->classname ) ); - } -} - -void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCRIPT_EVENT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pev->deadflag = DEAD_DYING; - // Kill me now! (and fade out when CineCleanup() is called) -#if _DEBUG - ALERT( at_aiconsole, "Death event: %s\n", STRING(pev->classname) ); -#endif - pev->health = 0; - } -#if _DEBUG - else - ALERT( at_aiconsole, "INVALID death event:%s\n", STRING(pev->classname) ); -#endif - break; - case SCRIPT_EVENT_NOT_DEAD: - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pev->deadflag = DEAD_NO; - // This is for life/death sequences where the player can determine whether a character is dead or alive after the script - pev->health = pev->max_health; - } - break; - - case SCRIPT_EVENT_SOUND: // Play a named wave file - EMIT_SOUND( edict(), CHAN_BODY, pEvent->options, 1.0, ATTN_IDLE ); - break; - - case SCRIPT_EVENT_SOUND_VOICE: - EMIT_SOUND( edict(), CHAN_VOICE, pEvent->options, 1.0, ATTN_IDLE ); - break; - - case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 33% of the time - if (RANDOM_LONG(0,2) == 0) - break; - // fall through... - case SCRIPT_EVENT_SENTENCE: // Play a named sentence group - SENTENCEG_PlayRndSz( edict(), pEvent->options, 1.0, ATTN_IDLE, 0, 100 ); - break; - - case SCRIPT_EVENT_FIREEVENT: // Fire a trigger - FireTargets( pEvent->options, this, this, USE_TOGGLE, 0 ); - break; - - case SCRIPT_EVENT_NOINTERRUPT: // Can't be interrupted from now on - if ( m_pCine ) - m_pCine->AllowInterrupt( FALSE ); - break; - - case SCRIPT_EVENT_CANINTERRUPT: // OK to interrupt now - if ( m_pCine ) - m_pCine->AllowInterrupt( TRUE ); - break; - -#if 0 - case SCRIPT_EVENT_INAIR: // Don't DROP_TO_FLOOR() - case SCRIPT_EVENT_ENDANIMATION: // Set ending animation sequence to - break; -#endif - - case MONSTER_EVENT_BODYDROP_HEAVY: - if ( pev->flags & FL_ONGROUND ) - { - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM, 0, 90 ); - } - else - { - EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM, 0, 90 ); - } - } - break; - - case MONSTER_EVENT_BODYDROP_LIGHT: - if ( pev->flags & FL_ONGROUND ) - { - if ( RANDOM_LONG( 0, 1 ) == 0 ) - { - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop3.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/bodydrop4.wav", 1, ATTN_NORM ); - } - } - break; - - case MONSTER_EVENT_SWISHSOUND: - { - // NO MONSTER may use this anim event unless that monster's precache precaches this sound!!! - EMIT_SOUND( ENT(pev), CHAN_BODY, "zombie/claw_miss2.wav", 1, ATTN_NORM ); - break; - } - - default: - ALERT( at_aiconsole, "Unhandled animation event %d for %s\n", pEvent->event, STRING(pev->classname) ); - break; - - } -} - - -// Combat - -Vector CBaseMonster :: GetGunPosition( ) -{ - UTIL_MakeVectors(pev->angles); - - // Vector vecSrc = pev->origin + gpGlobals->v_forward * 10; - //vecSrc.z = pevShooter->absmin.z + pevShooter->size.z * 0.7; - //vecSrc.z = pev->origin.z + (pev->view_ofs.z - 4); - Vector vecSrc = pev->origin - + gpGlobals->v_forward * m_HackedGunPos.y - + gpGlobals->v_right * m_HackedGunPos.x - + gpGlobals->v_up * m_HackedGunPos.z; - - return vecSrc; -} - - - - - -//========================================================= -// NODE GRAPH -//========================================================= - - - - - -//========================================================= -// FGetNodeRoute - tries to build an entire node path from -// the callers origin to the passed vector. If this is -// possible, ROUTE_SIZE waypoints will be copied into the -// callers m_Route. TRUE is returned if the operation -// succeeds (path is valid) or FALSE if failed (no path -// exists ) -//========================================================= -BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) -{ - int iPath[ MAX_PATH_SIZE ]; - int iSrcNode, iDestNode; - int iResult; - int i; - int iNumToCopy; - - iSrcNode = WorldGraph.FindNearestNode ( pev->origin, this ); - iDestNode = WorldGraph.FindNearestNode ( vecDest, this ); - - if ( iSrcNode == -1 ) - { - // no node nearest self -// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near self!\n" ); - return FALSE; - } - else if ( iDestNode == -1 ) - { - // no node nearest target -// ALERT ( at_aiconsole, "FGetNodeRoute: No valid node near target!\n" ); - return FALSE; - } - - // valid src and dest nodes were found, so it's safe to proceed with - // find shortest path - int iNodeHull = WorldGraph.HullIndex( this ); // make this a monster virtual function - iResult = WorldGraph.FindShortestPath ( iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability ); - - if ( !iResult ) - { -#if 1 - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); - return FALSE; -#else - BOOL bRoutingSave = WorldGraph.m_fRoutingComplete; - WorldGraph.m_fRoutingComplete = FALSE; - iResult = WorldGraph.FindShortestPath(iPath, iSrcNode, iDestNode, iNodeHull, m_afCapability); - WorldGraph.m_fRoutingComplete = bRoutingSave; - if ( !iResult ) - { - ALERT ( at_aiconsole, "No Path from %d to %d!\n", iSrcNode, iDestNode ); - return FALSE; - } - else - { - ALERT ( at_aiconsole, "Routing is inconsistent!" ); - } -#endif - } - - // there's a valid path within iPath now, so now we will fill the route array - // up with as many of the waypoints as it will hold. - - // don't copy ROUTE_SIZE entries if the path returned is shorter - // than ROUTE_SIZE!!! - if ( iResult < ROUTE_SIZE ) - { - iNumToCopy = iResult; - } - else - { - iNumToCopy = ROUTE_SIZE; - } - - for ( i = 0 ; i < iNumToCopy; i++ ) - { - m_Route[ i ].vecLocation = WorldGraph.m_pNodes[ iPath[ i ] ].m_vecOrigin; - m_Route[ i ].iType = bits_MF_TO_NODE; - } - - if ( iNumToCopy < ROUTE_SIZE ) - { - m_Route[ iNumToCopy ].vecLocation = vecDest; - m_Route[ iNumToCopy ].iType |= bits_MF_IS_GOAL; - } - - return TRUE; -} - -//========================================================= -// FindHintNode -//========================================================= -int CBaseMonster :: FindHintNode ( void ) -{ - int i; - TraceResult tr; - - if ( !WorldGraph.m_fGraphPresent ) - { - ALERT ( at_aiconsole, "find_hintnode: graph not ready!\n" ); - return NO_NODE; - } - - if ( WorldGraph.m_iLastActiveIdleSearch >= WorldGraph.m_cNodes ) - { - WorldGraph.m_iLastActiveIdleSearch = 0; - } - - for ( i = 0; i < WorldGraph.m_cNodes ; i++ ) - { - int nodeNumber = (i + WorldGraph.m_iLastActiveIdleSearch) % WorldGraph.m_cNodes; - CNode &node = WorldGraph.Node( nodeNumber ); - - if ( node.m_sHintType ) - { - // this node has a hint. Take it if it is visible, the monster likes it, and the monster has an animation to match the hint's activity. - if ( FValidateHintType ( node.m_sHintType ) ) - { - if ( !node.m_sHintActivity || LookupActivity ( node.m_sHintActivity ) != ACTIVITY_NOT_AVAILABLE ) - { - UTIL_TraceLine ( pev->origin + pev->view_ofs, node.m_vecOrigin + pev->view_ofs, ignore_monsters, ENT(pev), &tr ); - - if ( tr.flFraction == 1.0 ) - { - WorldGraph.m_iLastActiveIdleSearch = nodeNumber + 1; // next monster that searches for hint nodes will start where we left off. - return nodeNumber;// take it! - } - } - } - } - } - - WorldGraph.m_iLastActiveIdleSearch = 0;// start at the top of the list for the next search. - - return NO_NODE; -} - - -void CBaseMonster::ReportAIState( void ) -{ - ALERT_TYPE level = at_console; - - static const char *pStateNames[] = { "None", "Idle", "Combat", "Alert", "Hunt", "Prone", "Scripted", "Dead" }; - - ALERT( level, "%s: ", STRING(pev->classname) ); - if ( (int)m_MonsterState < ARRAYSIZE(pStateNames) ) - ALERT( level, "State: %s, ", pStateNames[m_MonsterState] ); - int i = 0; - while ( activity_map[i].type != 0 ) - { - if ( activity_map[i].type == (int)m_Activity ) - { - ALERT( level, "Activity %s, ", activity_map[i].name ); - break; - } - i++; - } - - if ( m_pSchedule ) - { - const char *pName = NULL; - pName = m_pSchedule->pName; - if ( !pName ) - pName = "Unknown"; - ALERT( level, "Schedule %s, ", pName ); - Task_t *pTask = GetTask(); - if ( pTask ) - ALERT( level, "Task %d (#%d), ", pTask->iTask, m_iScheduleIndex ); - } - else - ALERT( level, "No Schedule, " ); - - if ( m_hEnemy != 0 ) - ALERT( level, "\nEnemy is %s", STRING(m_hEnemy->pev->classname) ); - else - ALERT( level, "No enemy" ); - - if ( IsMoving() ) - { - ALERT( level, " Moving " ); - if ( m_flMoveWaitFinished > gpGlobals->time ) - ALERT( level, ": Stopped for %.2f. ", m_flMoveWaitFinished - gpGlobals->time ); - else if ( m_IdealActivity == GetStoppedActivity() ) - ALERT( level, ": In stopped anim. " ); - } - - CSquadMonster *pSquadMonster = MySquadMonsterPointer(); - - if ( pSquadMonster ) - { - if ( !pSquadMonster->InSquad() ) - { - ALERT ( level, "not " ); - } - - ALERT ( level, "In Squad, " ); - - if ( !pSquadMonster->IsLeader() ) - { - ALERT ( level, "not " ); - } - - ALERT ( level, "Leader." ); - } - - ALERT( level, "\n" ); - ALERT( level, "Yaw speed:%3.1f,Health: %3.1f\n", pev->yaw_speed, pev->health ); - if ( pev->spawnflags & SF_MONSTER_PRISONER ) - ALERT( level, " PRISONER! " ); - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) - ALERT( level, " Pre-Disaster! " ); - ALERT( level, "\n" ); -} - -//========================================================= -// KeyValue -// -// !!! netname entvar field is used in squadmonster for groupname!!! -//========================================================= -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "TriggerTarget")) - { - m_iszTriggerTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "TriggerCondition") ) - { - m_iTriggerCondition = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseToggle::KeyValue( pkvd ); - } -} - -//========================================================= -// FCheckAITrigger - checks the monster's AI Trigger Conditions, -// if there is a condition, then checks to see if condition is -// met. If yes, the monster's TriggerTarget is fired. -// -// Returns TRUE if the target is fired. -//========================================================= -BOOL CBaseMonster :: FCheckAITrigger ( void ) -{ - BOOL fFireTarget; - - if ( m_iTriggerCondition == AITRIGGER_NONE ) - { - // no conditions, so this trigger is never fired. - return FALSE; - } - - fFireTarget = FALSE; - - switch ( m_iTriggerCondition ) - { - case AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER: - if ( m_hEnemy != 0 && m_hEnemy->IsPlayer() && HasConditions ( bits_COND_SEE_ENEMY ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_SEEPLAYER_UNCONDITIONAL: - if ( HasConditions ( bits_COND_SEE_CLIENT ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_SEEPLAYER_NOT_IN_COMBAT: - if ( HasConditions ( bits_COND_SEE_CLIENT ) && - m_MonsterState != MONSTERSTATE_COMBAT && - m_MonsterState != MONSTERSTATE_PRONE && - m_MonsterState != MONSTERSTATE_SCRIPT) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_TAKEDAMAGE: - if ( m_afConditions & ( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_DEATH: - if ( pev->deadflag != DEAD_NO ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HALFHEALTH: - if ( IsAlive() && pev->health <= ( pev->max_health / 2 ) ) - { - fFireTarget = TRUE; - } - break; -/* - - // !!!UNDONE - no persistant game state that allows us to track these two. - - case AITRIGGER_SQUADMEMBERDIE: - break; - case AITRIGGER_SQUADLEADERDIE: - break; -*/ - case AITRIGGER_HEARWORLD: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_WORLD ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HEARPLAYER: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_PLAYER ) - { - fFireTarget = TRUE; - } - break; - case AITRIGGER_HEARCOMBAT: - if ( m_afConditions & bits_COND_HEAR_SOUND && m_afSoundTypes & bits_SOUND_COMBAT ) - { - fFireTarget = TRUE; - } - break; - } - - if ( fFireTarget ) - { - // fire the target, then set the trigger conditions to NONE so we don't fire again - ALERT ( at_aiconsole, "AI Trigger Fire Target\n" ); - FireTargets( STRING( m_iszTriggerTarget ), this, this, USE_TOGGLE, 0 ); - m_iTriggerCondition = AITRIGGER_NONE; - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CanPlaySequence - determines whether or not the monster -// can play the scripted sequence or AI sequence that is -// trying to possess it. If DisregardState is set, the monster -// will be sucked into the script no matter what state it is -// in. ONLY Scripted AI ents should allow this. -//========================================================= -int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) -{ - if ( m_pCine || !IsAlive() || m_MonsterState == MONSTERSTATE_PRONE ) - { - // monster is already running a scripted sequence or dead! - return FALSE; - } - - if ( fDisregardMonsterState ) - { - // ok to go, no matter what the monster state. (scripted AI) - return TRUE; - } - - if ( m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE ) - { - // ok to go, but only in these states - return TRUE; - } - - if ( m_MonsterState == MONSTERSTATE_ALERT && interruptLevel >= SS_INTERRUPT_BY_NAME ) - return TRUE; - - // unknown situation - return FALSE; -} - - -//========================================================= -// FindLateralCover - attempts to locate a spot in the world -// directly to the left or right of the caller that will -// conceal them from view of pSightEnt -//========================================================= -#define COVER_CHECKS 5// how many checks are made -#define COVER_DELTA 48// distance between checks - -BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) -{ - TraceResult tr; - Vector vecBestOnLeft; - Vector vecBestOnRight; - Vector vecLeftTest; - Vector vecRightTest; - Vector vecStepRight; - int i; - - UTIL_MakeVectors ( pev->angles ); - vecStepRight = gpGlobals->v_right * COVER_DELTA; - vecStepRight.z = 0; - - vecLeftTest = vecRightTest = pev->origin; - - for ( i = 0 ; i < COVER_CHECKS ; i++ ) - { - vecLeftTest = vecLeftTest - vecStepRight; - vecRightTest = vecRightTest + vecStepRight; - - // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. - UTIL_TraceLine( vecThreat + vecViewOffset, vecLeftTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if (tr.flFraction != 1.0) - { - if ( FValidateCover ( vecLeftTest ) && CheckLocalMove( pev->origin, vecLeftTest, NULL, NULL ) == LOCALMOVE_VALID ) - { - if ( MoveToLocation( ACT_RUN, 0, vecLeftTest ) ) - { - return TRUE; - } - } - } - - // it's faster to check the SightEnt's visibility to the potential spot than to check the local move, so we do that first. - UTIL_TraceLine(vecThreat + vecViewOffset, vecRightTest + pev->view_ofs, ignore_monsters, ignore_glass, ENT(pev)/*pentIgnore*/, &tr); - - if ( tr.flFraction != 1.0 ) - { - if ( FValidateCover ( vecRightTest ) && CheckLocalMove( pev->origin, vecRightTest, NULL, NULL ) == LOCALMOVE_VALID ) - { - if ( MoveToLocation( ACT_RUN, 0, vecRightTest ) ) - { - return TRUE; - } - } - } - } - - return FALSE; -} - - -Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) -{ - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy ) - { - return ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP - shootOrigin ).Normalize(); - } - else - return gpGlobals->v_forward; -} - - - -//========================================================= -// FacingIdeal - tells us if a monster is facing its ideal -// yaw. Created this function because many spots in the -// code were checking the yawdiff against this magic -// number. Nicer to have it in one place if we're gonna -// be stuck with it. -//========================================================= -BOOL CBaseMonster :: FacingIdeal( void ) -{ - if ( fabs( FlYawDiff() ) <= 0.006 )//!!!BUGBUG - no magic numbers!!! - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// FCanActiveIdle -//========================================================= -BOOL CBaseMonster :: FCanActiveIdle ( void ) -{ - /* - if ( m_MonsterState == MONSTERSTATE_IDLE && m_IdealMonsterState == MONSTERSTATE_IDLE && !IsMoving() ) - { - return TRUE; - } - */ - return FALSE; -} - - -void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) -{ - if ( pszSentence && IsAlive() ) - { - if ( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, PITCH_NORM ); - else - SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, PITCH_NORM ); - } -} - - -void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - PlaySentence( pszSentence, duration, volume, attenuation ); -} - - -void CBaseMonster::SentenceStop( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, "common/null.wav", 1.0, ATTN_IDLE ); -} - - -void CBaseMonster::CorpseFallThink( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - SetThink ( NULL ); - - SetSequenceBox( ); - UTIL_SetOrigin( pev, pev->origin );// link into world. - } - else - pev->nextthink = gpGlobals->time + 0.1; -} - -// Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) -{ - InitBoneControllers(); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground - - pev->frame = 0; - ResetSequenceInfo( ); - pev->framerate = 0; - - // Copy health - pev->max_health = pev->health; - pev->deadflag = DEAD_DEAD; - - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - UTIL_SetOrigin( pev, pev->origin ); - - // Setup health counters, etc. - BecomeDead(); - SetThink( &CBaseMonster::CorpseFallThink ); - pev->nextthink = gpGlobals->time + 0.5; -} - -//========================================================= -// BBoxIsFlat - check to see if the monster's bounding box -// is lying flat on a surface (traces from all four corners -// are same length.) -//========================================================= -BOOL CBaseMonster :: BBoxFlat ( void ) -{ - TraceResult tr; - Vector vecPoint; - float flXSize, flYSize; - float flLength; - float flLength2; - - flXSize = pev->size.x / 2; - flYSize = pev->size.y / 2; - - vecPoint.x = pev->origin.x + flXSize; - vecPoint.y = pev->origin.y + flYSize; - vecPoint.z = pev->origin.z; - - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength = (vecPoint - tr.vecEndPos).Length(); - - vecPoint.x = pev->origin.x - flXSize; - vecPoint.y = pev->origin.y - flYSize; - - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - vecPoint.x = pev->origin.x - flXSize; - vecPoint.y = pev->origin.y + flYSize; - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - vecPoint.x = pev->origin.x + flXSize; - vecPoint.y = pev->origin.y - flYSize; - UTIL_TraceLine ( vecPoint, vecPoint - Vector ( 0, 0, 100 ), ignore_monsters, ENT(pev), &tr ); - flLength2 = (vecPoint - tr.vecEndPos).Length(); - if ( flLength2 > flLength ) - { - return FALSE; - } - flLength = flLength2; - - return TRUE; -} - -//========================================================= -// Get Enemy - tries to find the best suitable enemy for the monster. -//========================================================= -BOOL CBaseMonster :: GetEnemy ( void ) -{ - CBaseEntity *pNewEnemy; - - if ( HasConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_NEMESIS) ) - { - pNewEnemy = BestVisibleEnemy(); - - if ( pNewEnemy != m_hEnemy && pNewEnemy != NULL) - { - // DO NOT mess with the monster's m_hEnemy pointer unless the schedule the monster is currently running will be interrupted - // by COND_NEW_ENEMY. This will eliminate the problem of monsters getting a new enemy while they are in a schedule that doesn't care, - // and then not realizing it by the time they get to a schedule that does. I don't feel this is a good permanent fix. - - if ( m_pSchedule ) - { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) - { - PushEnemy( m_hEnemy, m_vecEnemyLKP ); - SetConditions(bits_COND_NEW_ENEMY); - m_hEnemy = pNewEnemy; - m_vecEnemyLKP = m_hEnemy->pev->origin; - } - // if the new enemy has an owner, take that one as well - if (pNewEnemy->pev->owner != NULL) - { - CBaseEntity *pOwner = GetMonsterPointer( pNewEnemy->pev->owner ); - if ( pOwner && (pOwner->pev->flags & FL_MONSTER) && IRelationship( pOwner ) != R_NO ) - PushEnemy( pOwner, m_vecEnemyLKP ); - } - } - } - } - - // remember old enemies - if (m_hEnemy == 0 && PopEnemy( )) - { - if ( m_pSchedule ) - { - if ( m_pSchedule->iInterruptMask & bits_COND_NEW_ENEMY ) - { - SetConditions(bits_COND_NEW_ENEMY); - } - } - } - - if ( m_hEnemy != 0 ) - { - // monster has an enemy. - return TRUE; - } - - return FALSE;// monster has no enemy -} - - -//========================================================= -// DropItem - dead monster drops named item -//========================================================= -CBaseEntity* CBaseMonster :: DropItem ( const char *pszItemName, const Vector &vecPos, const Vector &vecAng ) -{ - if ( !pszItemName ) - { - ALERT ( at_console, "DropItem() - No item name!\n" ); - return NULL; - } - - CBaseEntity *pItem = CBaseEntity::Create( pszItemName, vecPos, vecAng, edict() ); - - if ( pItem ) - { - // do we want this behavior to be default?! (sjb) - pItem->pev->velocity = pev->velocity; - pItem->pev->avelocity = Vector ( 0, RANDOM_FLOAT( 0, 100 ), 0 ); - return pItem; - } - else - { - ALERT ( at_console, "DropItem() - Didn't create!\n" ); - return FALSE; - } - -} - - -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) -{ - // if flagged to fade out or I have an owner (I came from a monster spawner) - if ( (pev->spawnflags & SF_MONSTER_FADECORPSE) || !FNullEnt( pev->owner ) ) - return TRUE; - - return FALSE; -} diff --git a/sdk/dlls/monsters.h b/sdk/dlls/monsters.h deleted file mode 100644 index af0870a..0000000 --- a/sdk/dlls/monsters.h +++ /dev/null @@ -1,183 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef MONSTERS_H -#include "skill.h" -#define MONSTERS_H - -/* - -===== monsters.h ======================================================== - - Header file for monster-related utility code - -*/ - -// CHECKLOCALMOVE result types -#define LOCALMOVE_INVALID 0 // move is not possible -#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate -#define LOCALMOVE_VALID 2 // move is possible - -// Hit Group standards -#define HITGROUP_GENERIC 0 -#define HITGROUP_HEAD 1 -#define HITGROUP_CHEST 2 -#define HITGROUP_STOMACH 3 -#define HITGROUP_LEFTARM 4 -#define HITGROUP_RIGHTARM 5 -#define HITGROUP_LEFTLEG 6 -#define HITGROUP_RIGHTLEG 7 - - -// Monster Spawnflags -#define SF_MONSTER_WAIT_TILL_SEEN 1// spawnflag that makes monsters wait until player can see them before attacking. -#define SF_MONSTER_GAG 2 // no idle noises from this monster -#define SF_MONSTER_HITMONSTERCLIP 4 -// 8 -#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him. -// 32 -// 64 -#define SF_MONSTER_WAIT_FOR_SCRIPT 128 //spawnflag that makes monsters wait to check for attacking until the script is done or they've been attacked -#define SF_MONSTER_PREDISASTER 256 //this is a predisaster scientist or barney. Influences how they speak. -#define SF_MONSTER_FADECORPSE 512 // Fade out corpse after death -#define SF_MONSTER_FALL_TO_GROUND 0x80000000 - -// specialty spawnflags -#define SF_MONSTER_TURRET_AUTOACTIVATE 32 -#define SF_MONSTER_TURRET_STARTINACTIVE 64 -#define SF_MONSTER_WAIT_UNTIL_PROVOKED 64 // don't attack the player unless provoked - - - -// MoveToOrigin stuff -#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal -#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck. - - -// MoveToOrigin stuff -#define MOVE_NORMAL 0// normal move in the direction monster is facing -#define MOVE_STRAFE 1// moves in direction specified, no matter which way monster is facing - -// spawn flags 256 and above are already taken by the engine -extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType ); - -Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 ); -Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 ); -extern DLL_GLOBAL Vector g_vecAttackDir; -extern DLL_GLOBAL CONSTANT float g_flMeleeRange; -extern DLL_GLOBAL CONSTANT float g_flMediumRange; -extern DLL_GLOBAL CONSTANT float g_flLongRange; -extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); -extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ); - -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget ); -BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); - -// monster to monster relationship types -#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. -#define R_FR -1// (FEAR)will run -#define R_NO 0// (NO RELATIONSHIP) disregard -#define R_DL 1// (DISLIKE) will attack -#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters -#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what - - -// these bits represent the monster's memory -#define MEMORY_CLEAR 0 -#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes. -#define bits_MEMORY_INCOVER ( 1 << 1 )// monster knows it is in a covered position. -#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily -#define bits_MEMORY_PATH_FINISHED ( 1 << 3 )// Finished monster path (just used by big momma for now) -#define bits_MEMORY_ON_PATH ( 1 << 4 )// Moving on a path -#define bits_MEMORY_MOVE_FAILED ( 1 << 5 )// Movement has already failed -#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched -#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed() -#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // Monster-specific memory -#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // Monster-specific memory - -// trigger conditions for scripted AI -// these MUST match the CHOICES interface in halflife.fgd for the base monster -enum -{ - AITRIGGER_NONE = 0, - AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER, - AITRIGGER_TAKEDAMAGE, - AITRIGGER_HALFHEALTH, - AITRIGGER_DEATH, - AITRIGGER_SQUADMEMBERDIE, - AITRIGGER_SQUADLEADERDIE, - AITRIGGER_HEARWORLD, - AITRIGGER_HEARPLAYER, - AITRIGGER_HEARCOMBAT, - AITRIGGER_SEEPLAYER_UNCONDITIONAL, - AITRIGGER_SEEPLAYER_NOT_IN_COMBAT, -}; -/* - 0 : "No Trigger" - 1 : "See Player" - 2 : "Take Damage" - 3 : "50% Health Remaining" - 4 : "Death" - 5 : "Squad Member Dead" - 6 : "Squad Leader Dead" - 7 : "Hear World" - 8 : "Hear Player" - 9 : "Hear Combat" -*/ - -// -// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc. -// -class CGib : public CBaseEntity -{ -public: - void Spawn( const char *szGibModel ); - void EXPORT BounceGibTouch ( CBaseEntity *pOther ); - void EXPORT StickyGibTouch ( CBaseEntity *pOther ); - void EXPORT WaitTillLand( void ); - void LimitVelocity( void ); - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - static void SpawnHeadGib( entvars_t *pevVictim ); - static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ); - static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ); - - int m_bloodColor; - int m_cBloodDecals; - int m_material; - float m_lifeTime; -}; - - -#define CUSTOM_SCHEDULES\ - virtual Schedule_t *ScheduleFromName( const char *pName );\ - static Schedule_t *m_scheduleList[]; - -#define DEFINE_CUSTOM_SCHEDULES(derivedClass)\ - Schedule_t *derivedClass::m_scheduleList[] = - -#define IMPLEMENT_CUSTOM_SCHEDULES(derivedClass, baseClass)\ - Schedule_t *derivedClass::ScheduleFromName( const char *pName )\ - {\ - Schedule_t *pSchedule = ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) );\ - if ( !pSchedule )\ - return baseClass::ScheduleFromName(pName);\ - return pSchedule;\ - } - - - -#endif //MONSTERS_H diff --git a/sdk/dlls/monsterstate.cpp b/sdk/dlls/monsterstate.cpp deleted file mode 100644 index b49b499..0000000 --- a/sdk/dlls/monsterstate.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monsterstate.cpp - base class monster functions for -// controlling core AI. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "soundent.h" - -//========================================================= -// SetState -//========================================================= -void CBaseMonster :: SetState ( MONSTERSTATE State ) -{ -/* - if ( State != m_MonsterState ) - { - ALERT ( at_aiconsole, "State Changed to %d\n", State ); - } -*/ - - switch( State ) - { - - // Drop enemy pointers when going to idle - case MONSTERSTATE_IDLE: - - if ( m_hEnemy != 0 ) - { - m_hEnemy = NULL;// not allowed to have an enemy anymore. - ALERT ( at_aiconsole, "Stripped\n" ); - } - break; - default: - break; - } - - m_MonsterState = State; - m_IdealMonsterState = State; -} - -//========================================================= -// RunAI -//========================================================= -void CBaseMonster :: RunAI ( void ) -{ - // to test model's eye height - //UTIL_ParticleEffect ( pev->origin + pev->view_ofs, g_vecZero, 255, 10 ); - - // IDLE sound permitted in ALERT state is because monsters were silent in ALERT state. Only play IDLE sound in IDLE state - // once we have sounds for that state. - if ( ( m_MonsterState == MONSTERSTATE_IDLE || m_MonsterState == MONSTERSTATE_ALERT ) && RANDOM_LONG(0,99) == 0 && !(pev->flags & SF_MONSTER_GAG) ) - { - IdleSound(); - } - - if ( m_MonsterState != MONSTERSTATE_NONE && - m_MonsterState != MONSTERSTATE_PRONE && - m_MonsterState != MONSTERSTATE_DEAD )// don't bother with this crap if monster is prone. - { - // collect some sensory Condition information. - // don't let monsters outside of the player's PVS act up, or most of the interesting - // things will happen before the player gets there! - // UPDATE: We now let COMBAT state monsters think and act fully outside of player PVS. This allows the player to leave - // an area where monsters are fighting, and the fight will continue. - if ( !FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) || ( m_MonsterState == MONSTERSTATE_COMBAT ) ) - { - Look( m_flDistLook ); - Listen();// check for audible sounds. - - // now filter conditions. - ClearConditions( IgnoreConditions() ); - - GetEnemy(); - } - - // do these calculations if monster has an enemy. - if ( m_hEnemy != 0 ) - { - CheckEnemy( m_hEnemy ); - } - - CheckAmmo(); - } - - FCheckAITrigger(); - - PrescheduleThink(); - - MaintainSchedule(); - - // if the monster didn't use these conditions during the above call to MaintainSchedule() or CheckAITrigger() - // we throw them out cause we don't want them sitting around through the lifespan of a schedule - // that doesn't use them. - m_afConditions &= ~( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ); -} - -//========================================================= -// GetIdealState - surveys the Conditions information available -// and finds the best new state for a monster. -//========================================================= -MONSTERSTATE CBaseMonster :: GetIdealState ( void ) -{ - int iConditions; - - iConditions = IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - - /* - IDLE goes to ALERT upon hearing a sound - -IDLE goes to ALERT upon being injured - IDLE goes to ALERT upon seeing food - -IDLE goes to COMBAT upon sighting an enemy - IDLE goes to HUNT upon smelling food - */ - { - if ( iConditions & bits_COND_NEW_ENEMY ) - { - // new enemy! This means an idle monster has seen someone it dislikes, or - // that a monster in combat has found a more suitable target to attack - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } - else if ( iConditions & bits_COND_LIGHT_DAMAGE ) - { - MakeIdealYaw ( m_vecEnemyLKP ); - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - else if ( iConditions & bits_COND_HEAVY_DAMAGE ) - { - MakeIdealYaw ( m_vecEnemyLKP ); - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - else if ( iConditions & bits_COND_HEAR_SOUND ) - { - CSound *pSound; - - pSound = PBestSound(); - ASSERT( pSound != NULL ); - if ( pSound ) - { - MakeIdealYaw ( pSound->m_vecOrigin ); - if ( pSound->m_iType & (bits_SOUND_COMBAT|bits_SOUND_DANGER) ) - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - } - else if ( iConditions & (bits_COND_SMELL | bits_COND_SMELL_FOOD) ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - } - - break; - } - case MONSTERSTATE_ALERT: - /* - ALERT goes to IDLE upon becoming bored - -ALERT goes to COMBAT upon sighting an enemy - ALERT goes to HUNT upon hearing a noise - */ - { - if ( iConditions & (bits_COND_NEW_ENEMY|bits_COND_SEE_ENEMY) ) - { - // see an enemy we MUST attack - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } - else if ( iConditions & bits_COND_HEAR_SOUND ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - CSound *pSound = PBestSound(); - ASSERT( pSound != NULL ); - if ( pSound ) - MakeIdealYaw ( pSound->m_vecOrigin ); - } - break; - } - case MONSTERSTATE_COMBAT: - /* - COMBAT goes to HUNT upon losing sight of enemy - COMBAT goes to ALERT upon death of enemy - */ - { - if ( m_hEnemy == 0 ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - // pev->effects = EF_BRIGHTFIELD; - ALERT ( at_aiconsole, "***Combat state with no enemy!\n" ); - } - break; - } - case MONSTERSTATE_HUNT: - /* - HUNT goes to ALERT upon seeing food - HUNT goes to ALERT upon being injured - HUNT goes to IDLE if goal touched - HUNT goes to COMBAT upon seeing enemy - */ - { - break; - } - case MONSTERSTATE_SCRIPT: - if ( iConditions & (bits_COND_TASK_FAILED|bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) ) - { - ExitScriptedSequence(); // This will set the ideal state - } - break; - - case MONSTERSTATE_DEAD: - m_IdealMonsterState = MONSTERSTATE_DEAD; - break; - - default: - break; - } - - return m_IdealMonsterState; -} - diff --git a/sdk/dlls/mortar.cpp b/sdk/dlls/mortar.cpp deleted file mode 100644 index 5beda38..0000000 --- a/sdk/dlls/mortar.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== mortar.cpp ======================================================== - - the "LaBuznik" mortar device - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "weapons.h" -#include "decals.h" -#include "soundent.h" - -class CFuncMortarField : public CBaseToggle -{ -public: - void Spawn( void ); - void Precache( void ); - void KeyValue( KeyValueData *pkvd ); - - // Bmodels don't go across transitions - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - void EXPORT FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int m_iszXController; - int m_iszYController; - float m_flSpread; - float m_flDelay; - int m_iCount; - int m_fControl; -}; - -LINK_ENTITY_TO_CLASS( func_mortar_field, CFuncMortarField ); - -TYPEDESCRIPTION CFuncMortarField::m_SaveData[] = -{ - DEFINE_FIELD( CFuncMortarField, m_iszXController, FIELD_STRING ), - DEFINE_FIELD( CFuncMortarField, m_iszYController, FIELD_STRING ), - DEFINE_FIELD( CFuncMortarField, m_flSpread, FIELD_FLOAT ), - DEFINE_FIELD( CFuncMortarField, m_flDelay, FIELD_FLOAT ), - DEFINE_FIELD( CFuncMortarField, m_iCount, FIELD_INTEGER ), - DEFINE_FIELD( CFuncMortarField, m_fControl, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CFuncMortarField, CBaseToggle ); - - -void CFuncMortarField :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszXController")) - { - m_iszXController = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszYController")) - { - m_iszYController = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flSpread")) - { - m_flSpread = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fControl")) - { - m_fControl = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iCount")) - { - m_iCount = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - - -// Drop bombs from above -void CFuncMortarField :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_NONE; - SetBits( pev->effects, EF_NODRAW ); - SetUse( &CFuncMortarField::FieldUse ); - Precache(); -} - - -void CFuncMortarField :: Precache( void ) -{ - PRECACHE_SOUND ("weapons/mortar.wav"); - PRECACHE_SOUND ("weapons/mortarhit.wav"); - PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - - -// If connected to a table, then use the table controllers, else hit where the trigger is. -void CFuncMortarField :: FieldUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - Vector vecStart; - - vecStart.x = RANDOM_FLOAT( pev->mins.x, pev->maxs.x ); - vecStart.y = RANDOM_FLOAT( pev->mins.y, pev->maxs.y ); - vecStart.z = pev->maxs.z; - - switch( m_fControl ) - { - case 0: // random - break; - case 1: // Trigger Activator - if (pActivator != NULL) - { - vecStart.x = pActivator->pev->origin.x; - vecStart.y = pActivator->pev->origin.y; - } - break; - case 2: // table - { - CBaseEntity *pController; - - if (!FStringNull(m_iszXController)) - { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszXController)); - if (pController != NULL) - { - vecStart.x = pev->mins.x + pController->pev->ideal_yaw * (pev->size.x); - } - } - if (!FStringNull(m_iszYController)) - { - pController = UTIL_FindEntityByTargetname( NULL, STRING(m_iszYController)); - if (pController != NULL) - { - vecStart.y = pev->mins.y + pController->pev->ideal_yaw * (pev->size.y); - } - } - } - break; - } - - int pitch = RANDOM_LONG(95,124); - - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortar.wav", 1.0, ATTN_NONE, 0, pitch); - - float t = 2.5; - for (int i = 0; i < m_iCount; i++) - { - Vector vecSpot = vecStart; - vecSpot.x += RANDOM_FLOAT( -m_flSpread, m_flSpread ); - vecSpot.y += RANDOM_FLOAT( -m_flSpread, m_flSpread ); - - TraceResult tr; - UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pev), &tr ); - - edict_t *pentOwner = NULL; - if (pActivator) pentOwner = pActivator->edict(); - - CBaseEntity *pMortar = Create("monster_mortar", tr.vecEndPos, Vector( 0, 0, 0 ), pentOwner ); - pMortar->pev->nextthink = gpGlobals->time + t; - t += RANDOM_FLOAT( 0.2, 0.5 ); - - if (i == 0) - CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - } -} - - -class CMortar : public CGrenade -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT MortarExplode( void ); - - int m_spriteTexture; -}; - -LINK_ENTITY_TO_CLASS( monster_mortar, CMortar ); - -void CMortar::Spawn( ) -{ - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->dmg = 200; - - SetThink( &CMortar::MortarExplode ); - pev->nextthink = 0; - - Precache( ); - - -} - - -void CMortar::Precache( ) -{ - m_spriteTexture = PRECACHE_MODEL( "sprites/lgtning.spr" ); -} - -void CMortar::MortarExplode( void ) -{ -#if 1 - // mortar beam - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 1024); - WRITE_SHORT(m_spriteTexture ); - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 1 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 160 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); -#endif - -#if 0 - // blast circle - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMTORUS); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 32); - WRITE_COORD(pev->origin.x); - WRITE_COORD(pev->origin.y); - WRITE_COORD(pev->origin.z + 32 + pev->dmg * 2 / .2); // reach damage radius over .3 seconds - WRITE_SHORT(m_spriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 2 ); // life - WRITE_BYTE( 12 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 160 ); // r, g, b - WRITE_BYTE( 100 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); -#endif - - TraceResult tr; - UTIL_TraceLine( pev->origin + Vector( 0, 0, 1024 ), pev->origin - Vector( 0, 0, 1024 ), dont_ignore_monsters, ENT(pev), &tr ); - - Explode( &tr, DMG_BLAST | DMG_MORTAR ); - UTIL_ScreenShake( tr.vecEndPos, 25.0, 150.0, 1.0, 750 ); - -#if 0 - int pitch = RANDOM_LONG(95,124); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "weapons/mortarhit.wav", 1.0, 0.55, 0, pitch); - - // ForceSound( SNDRADIUS_MP5, bits_SOUND_COMBAT ); - - // ExplodeModel( pev->origin, 400, g_sModelIndexShrapnel, 30 ); - - RadiusDamage ( pev, VARS(pev->owner), pev->dmg, CLASS_NONE, DMG_BLAST ); - - /* - if ( RANDOM_FLOAT ( 0 , 1 ) < 0.5 ) - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH1 ); - } - else - { - UTIL_DecalTrace( pTrace, DECAL_SCORCH2 ); - } - */ - - SetThink( &CMortar::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -#endif - -} - - -#if 0 -void CMortar::ShootTimed( EVARS *pevOwner, Vector vecStart, float time ) -{ - CMortar *pMortar = GetClassPtr( (CMortar *)NULL ); - pMortar->Spawn(); - - TraceResult tr; - UTIL_TraceLine( vecStart, vecStart + Vector( 0, 0, -1 ) * 4096, ignore_monsters, ENT(pMortar->pev), &tr ); - - pMortar->pev->nextthink = gpGlobals->time + time; - - UTIL_SetOrigin( pMortar->pev, tr.vecEndPos ); -} -#endif diff --git a/sdk/dlls/mp5.cpp b/sdk/dlls/mp5.cpp deleted file mode 100644 index 1c9faf5..0000000 --- a/sdk/dlls/mp5.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -enum mp5_e -{ - MP5_LONGIDLE = 0, - MP5_IDLE1, - MP5_LAUNCH, - MP5_RELOAD, - MP5_DEPLOY, - MP5_FIRE1, - MP5_FIRE2, - MP5_FIRE3, -}; - - - -LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 ); -LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 ); - - -//========================================================= -//========================================================= -int CMP5::SecondaryAmmoIndex( void ) -{ - return m_iSecondaryAmmoType; -} - -void CMP5::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmAR"); // hack to allow for old names - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmAR.mdl"); - m_iId = WEAPON_MP5; - - m_iDefaultAmmo = MP5_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CMP5::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmAR.mdl"); - PRECACHE_MODEL("models/w_9mmAR.mdl"); - PRECACHE_MODEL("models/p_9mmAR.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shellTE_MODEL - - PRECACHE_MODEL("models/grenade.mdl"); // grenade - - PRECACHE_MODEL("models/w_9mmARclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND("items/clipinsert1.wav"); - PRECACHE_SOUND("items/cliprelease1.wav"); - - PRECACHE_SOUND ("weapons/hks1.wav");// H to the K - PRECACHE_SOUND ("weapons/hks2.wav");// H to the K - PRECACHE_SOUND ("weapons/hks3.wav");// H to the K - - PRECACHE_SOUND( "weapons/glauncher.wav" ); - PRECACHE_SOUND( "weapons/glauncher2.wav" ); - - PRECACHE_SOUND ("weapons/357_cock1.wav"); - - m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" ); - m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" ); -} - -int CMP5::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = "ARgrenades"; - p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY; - p->iMaxClip = MP5_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_MP5; - p->iWeight = MP5_WEIGHT; - - return 1; -} - -int CMP5::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CMP5::Deploy( ) -{ - return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" ); -} - - -void CMP5::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_iClip <= 0) - { - PlayEmptySound(); - m_flNextPrimaryAttack = 0.15; - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - Vector vecDir; - -#ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) -#else - if ( !g_pGameRules->IsMultiplayer() ) -#endif - { - // optimized multiplayer. Widened to make it easier to hit a moving player - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // single player spread - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = GetNextAttackDelay(0.1); - - if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - - -void CMP5::SecondaryAttack( void ) -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0) - { - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; - - m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - // we don't add in player velocity anymore. - CGrenade::ShootContact( m_pPlayer->pev, - m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, - gpGlobals->v_forward * 800 ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - - m_flNextPrimaryAttack = GetNextAttackDelay(1); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. - - if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); -} - -void CMP5::Reload( void ) -{ - if ( m_pPlayer->ammo_9mm <= 0 ) - return; - - DefaultReload( MP5_MAX_CLIP, MP5_RELOAD, 1.5 ); -} - - -void CMP5::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - switch ( RANDOM_LONG( 0, 1 ) ) - { - case 0: - iAnim = MP5_LONGIDLE; - break; - - default: - case 1: - iAnim = MP5_IDLE1; - break; - } - - SendWeaponAnim( iAnim ); - - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. -} - - - -class CMP5AmmoClip : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmARclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmARclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_MP5CLIP_GIVE, "9mm", _9MM_MAX_CARRY) != -1); - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_mp5clip, CMP5AmmoClip ); -LINK_ENTITY_TO_CLASS( ammo_9mmAR, CMP5AmmoClip ); - - - -class CMP5Chainammo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_chainammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_chainammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_CHAINBOX_GIVE, "9mm", _9MM_MAX_CARRY) != -1); - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_9mmbox, CMP5Chainammo ); - - -class CMP5AmmoGrenade : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_ARgrenade.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_ARgrenade.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int bResult = (pOther->GiveAmmo( AMMO_M203BOX_GIVE, "ARgrenades", M203_GRENADE_MAX_CARRY ) != -1); - - if (bResult) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return bResult; - } -}; -LINK_ENTITY_TO_CLASS( ammo_mp5grenades, CMP5AmmoGrenade ); -LINK_ENTITY_TO_CLASS( ammo_ARgrenades, CMP5AmmoGrenade ); - - - - - - - - - - - - - - - - - - diff --git a/sdk/dlls/mpstubb.cpp b/sdk/dlls/mpstubb.cpp deleted file mode 100644 index 6c7a34a..0000000 --- a/sdk/dlls/mpstubb.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" -#include "nodes.h" -#include "talkmonster.h" - - -float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once - -/*********************************************************/ - - -CGraph WorldGraph; -void CGraph :: InitGraph( void ) { } -int CGraph :: FLoadGraph ( char *szMapName ) { return FALSE; } -int CGraph :: AllocNodes ( void ) { return FALSE; } -int CGraph :: CheckNODFile ( char *szMapName ) { return FALSE; } -int CGraph :: FSetGraphPointers ( void ) { return 0; } -void CGraph :: ShowNodeConnections ( int iNode ) { } -int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) { return 0; } - - -/*********************************************************/ - - -void CBaseMonster :: ReportAIState( void ) { } -float CBaseMonster :: ChangeYaw ( int speed ) { return 0; } -void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } - - -void CBaseMonster::CorpseFallThink( void ) -{ - if ( pev->flags & FL_ONGROUND ) - { - SetThink ( NULL ); - - SetSequenceBox( ); - UTIL_SetOrigin( pev, pev->origin );// link into world. - } - else - pev->nextthink = gpGlobals->time + 0.1; -} -// Call after animation/pose is set up -void CBaseMonster :: MonsterInitDead( void ) -{ - InitBoneControllers(); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_TOSS;// so he'll fall to ground - - pev->frame = 0; - ResetSequenceInfo( ); - pev->framerate = 0; - - // Copy health - pev->max_health = pev->health; - pev->deadflag = DEAD_DEAD; - - UTIL_SetSize(pev, g_vecZero, g_vecZero ); - UTIL_SetOrigin( pev, pev->origin ); - - // Setup health counters, etc. - BecomeDead(); - SetThink( &CBaseMonster::CorpseFallThink ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -BOOL CBaseMonster :: ShouldFadeOnDeath( void ) -{ - return FALSE; -} - -BOOL CBaseMonster :: FCheckAITrigger ( void ) -{ - return FALSE; -} - -void CBaseMonster :: KeyValue( KeyValueData *pkvd ) -{ - CBaseToggle::KeyValue( pkvd ); -} - -int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) -{ - static int iEnemy[14][14] = - { // NONE MACH PLYR HPASS HMIL AMIL APASS AMONST APREY APRED INSECT PLRALY PBWPN ABWPN - /*NONE*/ { R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*MACHINE*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_DL, R_DL }, - /*PLAYER*/ { R_NO ,R_DL ,R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_DL, R_DL }, - /*HUMANPASSIVE*/{ R_NO ,R_NO ,R_AL ,R_AL ,R_HT ,R_FR ,R_NO ,R_HT ,R_DL ,R_FR ,R_NO ,R_AL, R_NO, R_NO }, - /*HUMANMILITAR*/{ R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_HT ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_HT, R_NO, R_NO }, - /*ALIENMILITAR*/{ R_NO ,R_DL ,R_HT ,R_DL ,R_HT ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPASSIVE*/{ R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO, R_NO, R_NO }, - /*ALIENMONSTER*/{ R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREY */{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_NO ,R_FR ,R_NO ,R_DL, R_NO, R_NO }, - /*ALIENPREDATO*/{ R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO ,R_NO ,R_HT ,R_DL ,R_NO ,R_DL, R_NO, R_NO }, - /*INSECT*/ { R_FR ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR ,R_FR ,R_FR ,R_FR ,R_NO ,R_FR, R_NO, R_NO }, - /*PLAYERALLY*/ { R_NO ,R_DL ,R_AL ,R_AL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_NO, R_NO, R_NO }, - /*PBIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_DL ,R_NO ,R_DL, R_NO, R_DL }, - /*ABIOWEAPON*/ { R_NO ,R_NO ,R_DL ,R_DL ,R_DL ,R_AL ,R_NO ,R_DL ,R_DL ,R_NO ,R_NO ,R_DL, R_DL, R_NO } - }; - - return iEnemy[ Classify() ][ pTarget->Classify() ]; -} - - -//========================================================= -// Look - Base class monster function to find enemies or -// food by sight. iDistance is distance ( in units ) that the -// monster can see. -// -// Sets the sight bits of the m_afConditions mask to indicate -// which types of entities were sighted. -// Function also sets the Looker's m_pLink -// to the head of a link list that contains all visible ents. -// (linked via each ent's m_pLink field) -// -//========================================================= -void CBaseMonster :: Look ( int iDistance ) -{ - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT); - - m_pLink = NULL; - - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - - CBaseEntity *pList[100]; - - Vector delta = Vector( iDistance, iDistance, iDistance ); - - // Find only monsters/clients in box, NOT limited to PVS - int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER ); - for ( int i = 0; i < count; i++ ) - { - pSightEnt = pList[i]; - if ( pSightEnt != this && pSightEnt->pev->health > 0 ) - { - // the looker will want to consider this entity - // don't check anything else about an entity that can't be seen, or an entity that you don't care about. - if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) ) - { - if ( pSightEnt->IsPlayer() ) - { - // if we see a client, remember that (mostly for scripted AI) - iSighted |= bits_COND_SEE_CLIENT; - } - - pSightEnt->m_pLink = m_pLink; - m_pLink = pSightEnt; - - if ( pSightEnt == m_hEnemy ) - { - // we know this ent is visible, so if it also happens to be our enemy, store that now. - iSighted |= bits_COND_SEE_ENEMY; - } - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_NM: - iSighted |= bits_COND_SEE_NEMESIS; - break; - case R_HT: - iSighted |= bits_COND_SEE_HATE; - break; - case R_DL: - iSighted |= bits_COND_SEE_DISLIKE; - break; - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_AL: - break; - default: - ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - - SetConditions( iSighted ); -} - - -//========================================================= -// BestVisibleEnemy - this functions searches the link -// list whose head is the caller's m_pLink field, and returns -// a pointer to the enemy entity in that list that is nearest the -// caller. -// -// !!!UNDONE - currently, this only returns the closest enemy. -// we'll want to consider distance, relationship, attack types, back turned, etc. -//========================================================= -CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) -{ - CBaseEntity *pReturn; - CBaseEntity *pNextEnt; - int iNearest; - int iDist; - int iBestRelationship; - - iNearest = 8192;// so first visible entity will become the closest. - pNextEnt = m_pLink; - pReturn = NULL; - iBestRelationship = R_NO; - - while ( pNextEnt != NULL ) - { - if ( pNextEnt->IsAlive() ) - { - if ( IRelationship( pNextEnt) > iBestRelationship ) - { - // this entity is disliked MORE than the entity that we - // currently think is the best visible enemy. No need to do - // a distance check, just get mad at this one for now. - iBestRelationship = IRelationship ( pNextEnt ); - iNearest = static_cast(( pNextEnt->pev->origin - pev->origin ).Length()); - pReturn = pNextEnt; - } - else if ( IRelationship( pNextEnt) == iBestRelationship ) - { - // this entity is disliked just as much as the entity that - // we currently think is the best visible enemy, so we only - // get mad at it if it is closer. - iDist = static_cast(( pNextEnt->pev->origin - pev->origin ).Length()); - - if ( iDist <= iNearest ) - { - iNearest = iDist; - iBestRelationship = IRelationship ( pNextEnt ); - pReturn = pNextEnt; - } - } - } - - pNextEnt = pNextEnt->m_pLink; - } - - return pReturn; -} diff --git a/sdk/dlls/msvc10/hl.sln b/sdk/dlls/msvc10/hl.sln deleted file mode 100644 index 774622f..0000000 --- a/sdk/dlls/msvc10/hl.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hl", "hl.vcxproj", "{8990375D-17C1-C735-06D7-7E21FB453583}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8990375D-17C1-C735-06D7-7E21FB453583}.Debug|Win32.ActiveCfg = Debug|Win32 - {8990375D-17C1-C735-06D7-7E21FB453583}.Debug|Win32.Build.0 = Debug|Win32 - {8990375D-17C1-C735-06D7-7E21FB453583}.Release|Win32.ActiveCfg = Release|Win32 - {8990375D-17C1-C735-06D7-7E21FB453583}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/sdk/dlls/msvc10/hl.vcxproj b/sdk/dlls/msvc10/hl.vcxproj deleted file mode 100644 index 780ce8a..0000000 --- a/sdk/dlls/msvc10/hl.vcxproj +++ /dev/null @@ -1,509 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - - - - DynamicLibrary - false - - - DynamicLibrary - false - - - - - - - - - - - - - - - .\Releasehl\ - .\Releasehl\ - false - - - .\debughl\ - .\debughl\ - true - - - - MultiThreaded - OnlyExplicitInline - true - true - MaxSpeed - true - Level3 - true - ..\..\dlls;..\..\engine;..\..\common;..\..\pm_shared;..\..\game_shared;..\..\public;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;CLIENT_WEAPONS;%(PreprocessorDefinitions) - .\Releasehl\ - true - .\Releasehl\hl.pch - .\Releasehl\ - .\Releasehl\ - - - true - NDEBUG;%(PreprocessorDefinitions) - .\Releasehl\hl.tlb - true - Win32 - - - 0x0409 - NDEBUG;%(PreprocessorDefinitions) - - - true - .\Releasehl\hl.bsc - - - true - true - true - Windows - ..\hl.def - .\Releasehl\hl.dll - .\Releasehl\hl.lib - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - LIBCMTD;LIBCD;%(IgnoreSpecificDefaultLibraries) - - - call ..\..\filecopy.bat $(TargetDir)$(TargetName).dll $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).dll -call ..\..\filecopy.bat $(TargetDir)$(TargetName).pdb $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).pdb - Copying to dlls - $(ProjectDir)..\..\..\game\mod\dlls\$(InputName).dll;$(ProjectDir)..\..\..\game\mod\dlls\$(InputName).pdb;%(Outputs) - - - - - MultiThreadedDebug - Default - false - Disabled - true - Level3 - true - ProgramDatabase - ..\;..\..\dlls;..\..\engine;..\..\common;..\..\pm_shared;..\..\game_shared;..\..\public;%(AdditionalIncludeDirectories) - _DEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;CLIENT_WEAPONS;%(PreprocessorDefinitions) - .\debughl\ - true - .\debughl\hl.pch - .\debughl\ - .\debughl\ - - - true - _DEBUG;%(PreprocessorDefinitions) - .\debughl\hl.tlb - true - Win32 - - - 0x0409 - ..\..\engine;%(AdditionalIncludeDirectories) - _DEBUG;%(PreprocessorDefinitions) - - - true - .\debughl\hl.bsc - - - true - true - true - Windows - ..\hl.def - .\debughl\hl.dll - .\debughl\hl.lib - user32.lib;advapi32.lib;%(AdditionalDependencies) - LIBCMT;LIBC;%(IgnoreSpecificDefaultLibraries) - - - call ..\..\filecopy.bat $(TargetDir)$(TargetName).dll $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).dll -call ..\..\filecopy.bat $(TargetDir)$(TargetName).pdb $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).pdb - Copying to dlls - $(ProjectDir)..\..\..\game\mod\dlls\$(InputName).dll;$(ProjectDir)..\..\..\game\mod\dlls\$(InputName).pdb;%(Outputs) - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/dlls/msvc10/hl.vcxproj.filters b/sdk/dlls/msvc10/hl.vcxproj.filters deleted file mode 100644 index 0b7068a..0000000 --- a/sdk/dlls/msvc10/hl.vcxproj.filters +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/dlls/msvc11/hl.sln b/sdk/dlls/msvc11/hl.sln deleted file mode 100644 index 227ed6e..0000000 --- a/sdk/dlls/msvc11/hl.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hl", "hl.vcxproj", "{A91CB5FC-EF55-4E3E-B95C-E957863E5FEC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A91CB5FC-EF55-4E3E-B95C-E957863E5FEC}.Debug|Win32.ActiveCfg = Debug|Win32 - {A91CB5FC-EF55-4E3E-B95C-E957863E5FEC}.Debug|Win32.Build.0 = Debug|Win32 - {A91CB5FC-EF55-4E3E-B95C-E957863E5FEC}.Release|Win32.ActiveCfg = Release|Win32 - {A91CB5FC-EF55-4E3E-B95C-E957863E5FEC}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/sdk/dlls/msvc11/hl.vcxproj b/sdk/dlls/msvc11/hl.vcxproj deleted file mode 100644 index 56d5a30..0000000 --- a/sdk/dlls/msvc11/hl.vcxproj +++ /dev/null @@ -1,512 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - - - {A91CB5FC-EF55-4E3E-B95C-E957863E5FEC} - - - - DynamicLibrary - false - v110_xp - - - DynamicLibrary - false - v110_xp - - - - - - - - - - - - - - - .\Releasehl\ - .\Releasehl\ - false - - - .\debughl\ - .\debughl\ - true - - - - MultiThreaded - OnlyExplicitInline - true - true - MaxSpeed - true - Level3 - true - ..\..\dlls;..\..\engine;..\..\common;..\..\pm_shared;..\..\game_shared;..\..\public;%(AdditionalIncludeDirectories) - NDEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;CLIENT_WEAPONS;%(PreprocessorDefinitions) - .\Releasehl\ - true - .\Releasehl\hl.pch - .\Releasehl\ - .\Releasehl\ - - - true - NDEBUG;%(PreprocessorDefinitions) - .\Releasehl\hl.tlb - true - Win32 - - - 0x0409 - NDEBUG;%(PreprocessorDefinitions) - - - true - .\Releasehl\hl.bsc - - - true - true - true - Windows - ..\hl.def - .\Releasehl\hl.dll - .\Releasehl\hl.lib - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - LIBCMTD;LIBCD;%(IgnoreSpecificDefaultLibraries) - - - call ..\..\filecopy.bat $(TargetDir)$(TargetName).dll $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).dll -call ..\..\filecopy.bat $(TargetDir)$(TargetName).pdb $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).pdb - Copying to dlls - $(ProjectDir)..\..\..\game\mod\dlls\$(InputName).dll;$(ProjectDir)..\..\..\game\mod\dlls\$(InputName).pdb;%(Outputs) - - - - - MultiThreadedDebug - Default - false - Disabled - true - Level3 - true - ProgramDatabase - ..\;..\..\dlls;..\..\engine;..\..\common;..\..\pm_shared;..\..\game_shared;..\..\public;%(AdditionalIncludeDirectories) - _DEBUG;WIN32;_WINDOWS;QUIVER;VOXEL;QUAKE2;VALVE_DLL;CLIENT_WEAPONS;%(PreprocessorDefinitions) - .\debughl\ - true - .\debughl\hl.pch - .\debughl\ - .\debughl\ - - - true - _DEBUG;%(PreprocessorDefinitions) - .\debughl\hl.tlb - true - Win32 - - - 0x0409 - ..\engine;%(AdditionalIncludeDirectories) - _DEBUG;%(PreprocessorDefinitions) - - - true - .\debughl\hl.bsc - - - true - true - true - Windows - ..\hl.def - .\debughl\hl.dll - .\debughl\hl.lib - user32.lib;advapi32.lib;%(AdditionalDependencies) - LIBCMT;LIBC;%(IgnoreSpecificDefaultLibraries) - - - call ..\..\filecopy.bat $(TargetDir)$(TargetName).dll $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).dll -call ..\..\filecopy.bat $(TargetDir)$(TargetName).pdb $(ProjectDir)..\..\..\game\mod\dlls\$(TargetName).pdb - Copying to dlls - $(ProjectDir)..\..\..\game\mod\dlls\$(InputName).dll;$(ProjectDir)..\..\..\game\mod\dlls\$(InputName).pdb;%(Outputs) - - - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/dlls/msvc11/hl.vcxproj.filters b/sdk/dlls/msvc11/hl.vcxproj.filters deleted file mode 100644 index 0b7068a..0000000 --- a/sdk/dlls/msvc11/hl.vcxproj.filters +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sdk/dlls/multiplay_gamerules.cpp b/sdk/dlls/multiplay_gamerules.cpp deleted file mode 100644 index 8a26e3b..0000000 --- a/sdk/dlls/multiplay_gamerules.cpp +++ /dev/null @@ -1,1692 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" - -#include "skill.h" -#include "game.h" -#include "items.h" -#include "voice_gamemgr.h" -#include "hltv.h" - -#if !defined ( _WIN32 ) -#include -#endif - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int gmsgDeathMsg; // client dll messages -extern int gmsgScoreInfo; -extern int gmsgMOTD; -extern int gmsgServerName; - -extern int g_teamplay; - -#define ITEM_RESPAWN_TIME 30 -#define WEAPON_RESPAWN_TIME 20 -#define AMMO_RESPAWN_TIME 20 - -float g_flIntermissionStartTime = 0; - -CVoiceGameMgr g_VoiceGameMgr; - -class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper -{ -public: - virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) - { - if ( g_teamplay ) - { - if ( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) - { - return false; - } - } - - return true; - } -}; -static CMultiplayGameMgrHelper g_GameMgrHelper; - -//********************************************************* -// Rules for the half-life multiplayer game. -//********************************************************* - -CHalfLifeMultiplay :: CHalfLifeMultiplay() -{ - g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); - - RefreshSkillData(); - m_flIntermissionEndTime = 0; - g_flIntermissionStartTime = 0; - - // 11/8/98 - // Modified by YWB: Server .cfg file is now a cvar, so that - // server ops can run multiple game servers, with different server .cfg files, - // from a single installed directory. - // Mapcyclefile is already a cvar. - - // 3/31/99 - // Added lservercfg file cvar, since listen and dedicated servers should not - // share a single config file. (sjb) - if ( IS_DEDICATED_SERVER() ) - { - // this code has been moved into engine, to only run server.cfg once - } - else - { - // listen server - char *lservercfgfile = (char *)CVAR_GET_STRING( "lservercfgfile" ); - - if ( lservercfgfile && lservercfgfile[0] ) - { - char szCommand[256]; - - ALERT( at_console, "Executing listen server config file\n" ); - sprintf( szCommand, "exec %s\n", lservercfgfile ); - SERVER_COMMAND( szCommand ); - } - } -} - -BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) - return TRUE; - - return CGameRules::ClientCommand(pPlayer, pcmd); -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::RefreshSkillData( void ) -{ -// load all default values - CGameRules::RefreshSkillData(); - -// override some values for multiplay. - - // suitcharger - gSkillData.suitchargerCapacity = 30; - - // Crowbar whack - gSkillData.plrDmgCrowbar = 25; - - // Glock Round - gSkillData.plrDmg9MM = 12; - - // 357 Round - gSkillData.plrDmg357 = 40; - - // MP5 Round - gSkillData.plrDmgMP5 = 12; - - // M203 grenade - gSkillData.plrDmgM203Grenade = 100; - - // Shotgun buckshot - gSkillData.plrDmgBuckshot = 20;// fewer pellets in deathmatch - - // Crossbow - gSkillData.plrDmgCrossbowClient = 20; - - // RPG - gSkillData.plrDmgRPG = 120; - - // Egon - gSkillData.plrDmgEgonWide = 20; - gSkillData.plrDmgEgonNarrow = 10; - - // Hand Grendade - gSkillData.plrDmgHandGrenade = 100; - - // Satchel Charge - gSkillData.plrDmgSatchel = 120; - - // Tripmine - gSkillData.plrDmgTripmine = 150; - - // hornet - gSkillData.plrDmgHornet = 10; -} - -// longest the intermission can last, in seconds -#define MAX_INTERMISSION_TIME 120 - -extern cvar_t timeleft, fragsleft; - -extern cvar_t mp_chattime; - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: Think ( void ) -{ - g_VoiceGameMgr.Update(gpGlobals->frametime); - - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - if ( g_fGameOver ) // someone else quit the game already - { - // bounds check - int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) - CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = g_flIntermissionStartTime + mp_chattime.value; - - // check to see if we should change levels now - if ( m_flIntermissionEndTime < gpGlobals->time ) - { - if ( m_iEndIntermissionButtonHit // check that someone has pressed a key, or the max intermission time is over - || ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time) ) - ChangeLevel(); // intermission is over - } - - return; - } - - float flTimeLimit = timelimit.value * 60; - float flFragLimit = fraglimit.value; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) - { - GoToIntermission(); - return; - } - - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any player is over the frag limit - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && pPlayer->pev->frags >= flFragLimit ) - { - GoToIntermission(); - return; - } - - - if ( pPlayer ) - { - remain = static_cast(flFragLimit - pPlayer->pev->frags); - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if ( timeleft.value != last_time ) - { - g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsMultiplayer( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsDeathmatch( void ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsCoOp( void ) -{ - return static_cast(gpGlobals->coop); -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - // that weapon can't deploy anyway. - return FALSE; - } - - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - // can't put away the active item. - return FALSE; - } - - if ( pWeapon->iWeight() > pPlayer->m_pActiveItem->iWeight() ) - { - return TRUE; - } - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - - CBasePlayerItem *pCheck; - CBasePlayerItem *pBest;// this will be used in the event that we don't find a weapon in the same category. - int iBestWeight; - int i; - - iBestWeight = -1;// no weapon lower than -1 can be autoswitched to - pBest = NULL; - - if ( !pCurrentWeapon->CanHolster() ) - { - // can't put this gun away right now, so can't switch. - return FALSE; - } - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pCheck = pPlayer->m_rgpPlayerItems[ i ]; - - while ( pCheck ) - { - if ( pCheck->iWeight() > -1 && pCheck->iWeight() == pCurrentWeapon->iWeight() && pCheck != pCurrentWeapon ) - { - // this weapon is from the same category. - if ( pCheck->CanDeploy() ) - { - if ( pPlayer->SwitchWeapon( pCheck ) ) - { - return TRUE; - } - } - } - else if ( pCheck->iWeight() > iBestWeight && pCheck != pCurrentWeapon )// don't reselect the weapon we're trying to get rid of - { - //ALERT ( at_console, "Considering %s\n", STRING( pCheck->pev->classname ) ); - // we keep updating the 'best' weapon just in case we can't find a weapon of the same weight - // that the player was using. This will end up leaving the player with his heaviest-weighted - // weapon. - if ( pCheck->CanDeploy() ) - { - // if this weapon is useable, flag it as the best - iBestWeight = pCheck->iWeight(); - pBest = pCheck; - } - } - - pCheck = pCheck->m_pNext; - } - } - - // if we make it here, we've checked all the weapons and found no useable - // weapon in the same catagory as the current weapon. - - // if pBest is null, we didn't find ANYTHING. Shouldn't be possible- should always - // at least get the crowbar, but ya never know. - if ( !pBest ) - { - return FALSE; - } - - pPlayer->SwitchWeapon( pBest ); - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - g_VoiceGameMgr.ClientConnected(pEntity); - return TRUE; -} - -extern int gmsgSayText; -extern int gmsgGameMode; - -void CHalfLifeMultiplay :: UpdateGameMode( CBasePlayer *pPlayer ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() ); - WRITE_BYTE( 0 ); // game mode none - MESSAGE_END(); -} - -void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl ) -{ - // notify other clients of player joining the game - UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", - ( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) ); - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n", - STRING( pl->pev->netname ), - GETPLAYERUSERID( pl->edict() ), - GETPLAYERAUTHID( pl->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pl->edict() ), "model" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" entered the game\n", - STRING( pl->pev->netname ), - GETPLAYERUSERID( pl->edict() ), - GETPLAYERAUTHID( pl->edict() ), - GETPLAYERUSERID( pl->edict() ) ); - } - - UpdateGameMode( pl ); - - // sending just one score makes the hud scoreboard active; otherwise - // it is just disabled for single play - MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); - WRITE_BYTE( ENTINDEX(pl->edict()) ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - WRITE_SHORT( 0 ); - MESSAGE_END(); - - SendMOTDToClient( pl->edict() ); - - // loop through all active players and send their score info to the new client - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - // FIXME: Probably don't need to cast this just to read m_iDeaths - CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i ); - - if ( plr ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() ); - WRITE_BYTE( i ); // client number - WRITE_SHORT( static_cast(plr->pev->frags) ); - WRITE_SHORT( plr->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( plr->m_szTeamName ) + 1 ); - MESSAGE_END(); - } - } - - if ( g_fGameOver ) - { - MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() ); - MESSAGE_END(); - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: ClientDisconnected( edict_t *pClient ) -{ - if ( pClient ) - { - CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); - - if ( pPlayer ) - { - FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", - STRING( pPlayer->pev->netname ), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ) ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" disconnected\n", - STRING( pPlayer->pev->netname ), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - GETPLAYERUSERID( pPlayer->edict() ) ); - } - - pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items - } - } -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - int iFallDamage = (int)falldamage.value; - - switch ( iFallDamage ) - { - case 1://progressive - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; - break; - default: - case 0:// fixed - return 10; - break; - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerThink( CBasePlayer *pPlayer ) -{ - if ( g_fGameOver ) - { - // check for button presses - if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) - m_iEndIntermissionButtonHit = TRUE; - - // clear attack/use commands from player - pPlayer->m_afButtonPressed = 0; - pPlayer->pev->button = 0; - pPlayer->m_afButtonReleased = 0; - } -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay :: PlayerSpawn( CBasePlayer *pPlayer ) -{ - BOOL addDefault; - CBaseEntity *pWeaponEntity = NULL; - - pPlayer->pev->weapons |= (1<Touch( pPlayer ); - addDefault = FALSE; - } - - if ( addDefault ) - { - pPlayer->GiveNamedItem( "weapon_crowbar" ); - pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); - pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads - } -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -BOOL CHalfLifeMultiplay :: AllowAutoTargetCrosshair( void ) -{ - return ( aimcrosshair.value != 0 ); -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeMultiplay :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeMultiplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - DeathNotice( pVictim, pKiller, pInflictor ); - - pVictim->m_iDeaths += 1; - - - FireTargets( "game_playerdie", pVictim, pVictim, USE_TOGGLE, 0 ); - CBasePlayer *peKiller = NULL; - CBaseEntity *ktmp = CBaseEntity::Instance( pKiller ); - if ( ktmp && (ktmp->Classify() == CLASS_PLAYER) ) - peKiller = (CBasePlayer*)ktmp; - - if ( pVictim->pev == pKiller ) - { // killed self - pKiller->frags -= 1; - } - else if ( ktmp && ktmp->IsPlayer() ) - { - // if a player dies in a deathmatch game and the killer is a client, award the killer some points - pKiller->frags += IPointsForKill( peKiller, pVictim ); - - FireTargets( "game_playerkill", ktmp, ktmp, USE_TOGGLE, 0 ); - } - else - { // killed by the world - pKiller->frags -= 1; - } - - // update the scores - // killed scores - MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); - WRITE_SHORT( static_cast(pVictim->pev->frags) ); - WRITE_SHORT( pVictim->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( pVictim->m_szTeamName ) + 1 ); - MESSAGE_END(); - - // killers score, if it's a player - CBaseEntity *ep = CBaseEntity::Instance( pKiller ); - if ( ep && ep->Classify() == CLASS_PLAYER ) - { - CBasePlayer *PK = (CBasePlayer*)ep; - - MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(PK->edict()) ); - WRITE_SHORT( static_cast(PK->pev->frags) ); - WRITE_SHORT( PK->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( GetTeamIndex( PK->m_szTeamName) + 1 ); - MESSAGE_END(); - - // let the killer paint another decal as soon as he'd like. - PK->m_flNextDecalTime = gpGlobals->time; - } -#ifndef HLDEMO_BUILD - if ( pVictim->HasNamedPlayerItem("weapon_satchel") ) - { - DeactivateSatchels( pVictim ); - } -#endif -} - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - // Work out what killed the player, and send a message to all clients about it - CBaseEntity::Instance( pKiller ); - - const char *killer_weapon_name = "world"; // by default, the player is killed by the world - int killer_index = 0; - - // Hack to fix name change - const char *tau = "tau_cannon"; - const char *gluon = "gluon gun"; - - if ( pKiller->flags & FL_CLIENT ) - { - killer_index = ENTINDEX(ENT(pKiller)); - - if ( pevInflictor ) - { - if ( pevInflictor == pKiller ) - { - // If the inflictor is the killer, then it must be their current weapon doing the damage - CBasePlayer *pPlayer = (CBasePlayer*)CBaseEntity::Instance( pKiller ); - - if ( pPlayer->m_pActiveItem ) - { - killer_weapon_name = pPlayer->m_pActiveItem->pszName(); - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); // it's just that easy - } - } - } - else - { - killer_weapon_name = STRING( pevInflictor->classname ); - } - - // strip the monster_* or weapon_* from the inflictor's classname - if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) - killer_weapon_name += 7; - else if ( strncmp( killer_weapon_name, "monster_", 8 ) == 0 ) - killer_weapon_name += 8; - else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) - killer_weapon_name += 5; - - MESSAGE_BEGIN( MSG_ALL, gmsgDeathMsg ); - WRITE_BYTE( killer_index ); // the killer - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim - WRITE_STRING( killer_weapon_name ); // what they were killed by (should this be a string?) - MESSAGE_END(); - - // replace the code names with the 'real' names - if ( !strcmp( killer_weapon_name, "egon" ) ) - killer_weapon_name = gluon; - else if ( !strcmp( killer_weapon_name, "gauss" ) ) - killer_weapon_name = tau; - - if ( pVictim->pev == pKiller ) - { - // killed self - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" committed suicide with \"%s\"\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - else if ( pKiller->flags & FL_CLIENT ) - { - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", - STRING( pKiller->netname ), - GETPLAYERUSERID( ENT(pKiller) ), - GETPLAYERAUTHID( ENT(pKiller) ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( ENT(pKiller) ), "model" ), - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" killed \"%s<%i><%s><%i>\" with \"%s\"\n", - STRING( pKiller->netname ), - GETPLAYERUSERID( ENT(pKiller) ), - GETPLAYERAUTHID( ENT(pKiller) ), - GETPLAYERUSERID( ENT(pKiller) ), - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - else - { - // killed by the world - - // team match? - if ( g_teamplay ) - { - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pVictim->edict() ), "model" ), - killer_weapon_name ); - } - else - { - UTIL_LogPrintf( "\"%s<%i><%s><%i>\" committed suicide with \"%s\" (world)\n", - STRING( pVictim->pev->netname ), - GETPLAYERUSERID( pVictim->edict() ), - GETPLAYERAUTHID( pVictim->edict() ), - GETPLAYERUSERID( pVictim->edict() ), - killer_weapon_name ); - } - } - - MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); - WRITE_BYTE ( 9 ); // command length in bytes - WRITE_BYTE ( DRC_CMD_EVENT ); // player killed - WRITE_SHORT( ENTINDEX(pVictim->edict()) ); // index number of primary entity - if (pevInflictor) - WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity - else - WRITE_SHORT( ENTINDEX(ENT(pKiller)) ); // index number of secondary entity - WRITE_LONG( 7 | DRC_FLAG_DRAMATIC); // eventflags (priority and flags) - MESSAGE_END(); - -// Print a standard message - // TODO: make this go direct to console - return; // just remove for now -/* - char szText[ 128 ]; - - if ( pKiller->flags & FL_MONSTER ) - { - // killed by a monster - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was killed by a monster.\n" ); - return; - } - - if ( pKiller == pVictim->pev ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " commited suicide.\n" ); - } - else if ( pKiller->flags & FL_CLIENT ) - { - strcpy ( szText, STRING( pKiller->netname ) ); - - strcat( szText, " : " ); - strcat( szText, killer_weapon_name ); - strcat( szText, " : " ); - - strcat ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, "\n" ); - } - else if ( FClassnameIs ( pKiller, "worldspawn" ) ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " fell or drowned or something.\n" ); - } - else if ( pKiller->solid == SOLID_BSP ) - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " was mooshed.\n" ); - } - else - { - strcpy ( szText, STRING( pVictim->pev->netname ) ); - strcat ( szText, " died mysteriously.\n" ); - } - - UTIL_ClientPrintAll( szText ); -*/ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeMultiplay :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeMultiplay :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) -{ - if ( weaponstay.value > 0 ) - { - // make sure it's only certain weapons - if ( !(pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - return gpGlobals->time + 0; // weapon respawns almost instantly - } - } - - return gpGlobals->time + WEAPON_RESPAWN_TIME; -} - -// when we are within this close to running out of entities, items -// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn -#define ENTITY_INTOLERANCE 100 - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeMultiplay :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) -{ - if ( pWeapon && pWeapon->m_iId && (pWeapon->iFlags() & ITEM_FLAG_LIMITINWORLD) ) - { - if ( NUMBER_OF_ENTITIES() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) ) - return 0; - - // we're past the entity tolerance level, so delay the respawn - return FlWeaponRespawnTime( pWeapon ); - } - - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeMultiplay :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeMultiplay :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) -{ - if ( pWeapon->pev->spawnflags & SF_NORESPAWN ) - { - return GR_WEAPON_RESPAWN_NO; - } - - return GR_WEAPON_RESPAWN_YES; -} - -//========================================================= -// CanHaveWeapon - returns FALSE if the player is not allowed -// to pick up this weapon -//========================================================= -BOOL CHalfLifeMultiplay::CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pItem ) -{ - if ( weaponstay.value > 0 ) - { - if ( pItem->iFlags() & ITEM_FLAG_LIMITINWORLD ) - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); - - // check if the player already has this weapon - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - CBasePlayerItem *it = pPlayer->m_rgpPlayerItems[i]; - - while ( it != NULL ) - { - if ( it->m_iId == pItem->m_iId ) - { - return FALSE; - } - - it = it->m_pNext; - } - } - } - - return CGameRules::CanHavePlayerItem( pPlayer, pItem ); -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::ItemShouldRespawn( CItem *pItem ) -{ - if ( pItem->pev->spawnflags & SF_NORESPAWN ) - { - return GR_ITEM_RESPAWN_NO; - } - - return GR_ITEM_RESPAWN_YES; -} - - -//========================================================= -// At what time in the future may this Item respawn? -//========================================================= -float CHalfLifeMultiplay::FlItemRespawnTime( CItem *pItem ) -{ - return gpGlobals->time + ITEM_RESPAWN_TIME; -} - -//========================================================= -// Where should this item respawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeMultiplay::VecItemRespawnSpot( CItem *pItem ) -{ - return pItem->pev->origin; -} - -//========================================================= -//========================================================= -void CHalfLifeMultiplay::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ -// if ( pEntity->pev->flags & FL_MONSTER ) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) -{ - if ( pAmmo->pev->spawnflags & SF_NORESPAWN ) - { - return GR_AMMO_RESPAWN_NO; - } - - return GR_AMMO_RESPAWN_YES; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) -{ - return gpGlobals->time + AMMO_RESPAWN_TIME; -} - -//========================================================= -//========================================================= -Vector CHalfLifeMultiplay::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) -{ - return pAmmo->pev->origin; -} - -//========================================================= -//========================================================= -float CHalfLifeMultiplay::FlHealthChargerRechargeTime( void ) -{ - return 60; -} - - -float CHalfLifeMultiplay::FlHEVChargerRechargeTime( void ) -{ - return 30; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_ACTIVE; -} - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_ACTIVE; -} - -edict_t *CHalfLifeMultiplay::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - edict_t *pentSpawnSpot = CGameRules::GetPlayerSpawnSpot( pPlayer ); - if ( IsMultiplayer() && pentSpawnSpot->v.target ) - { - FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); - } - - return pentSpawnSpot; -} - - -//========================================================= -//========================================================= -int CHalfLifeMultiplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life deathmatch has only enemies - return GR_NOTTEAMMATE; -} - -BOOL CHalfLifeMultiplay :: PlayFootstepSounds( CBasePlayer *pl, float fvol ) -{ - if ( g_footsteps && g_footsteps->value == 0 ) - return FALSE; - - if ( pl->IsOnLadder() || pl->pev->velocity.Length2D() > 220 ) - return TRUE; // only make step sounds in multiplayer if the player is moving fast enough - - return FALSE; -} - -BOOL CHalfLifeMultiplay :: FAllowFlashlight( void ) -{ - return flashlight.value != 0; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeMultiplay :: FAllowMonsters( void ) -{ - return ( allowmonsters.value != 0 ); -} - -//========================================================= -//======== CHalfLifeMultiplay private functions =========== -#define INTERMISSION_TIME 6 - -void CHalfLifeMultiplay :: GoToIntermission( void ) -{ - if ( g_fGameOver ) - return; // intermission has already been triggered, so ignore. - - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); - MESSAGE_END(); - - // bounds check - int time = (int)CVAR_GET_FLOAT( "mp_chattime" ); - if ( time < 1 ) - CVAR_SET_STRING( "mp_chattime", "1" ); - else if ( time > MAX_INTERMISSION_TIME ) - CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) ); - - m_flIntermissionEndTime = gpGlobals->time + ( (int)mp_chattime.value ); - g_flIntermissionStartTime = gpGlobals->time; - - g_fGameOver = TRUE; - m_iEndIntermissionButtonHit = FALSE; -} - -#define MAX_RULE_BUFFER 1024 - -typedef struct mapcycle_item_s -{ - struct mapcycle_item_s *next; - - char mapname[ 32 ]; - int minplayers, maxplayers; - char rulebuffer[ MAX_RULE_BUFFER ]; -} mapcycle_item_t; - -typedef struct mapcycle_s -{ - struct mapcycle_item_s *items; - struct mapcycle_item_s *next_item; -} mapcycle_t; - -/* -============== -DestroyMapCycle - -Clean up memory used by mapcycle when switching it -============== -*/ -void DestroyMapCycle( mapcycle_t *cycle ) -{ - mapcycle_item_t *p, *n, *start; - p = cycle->items; - if ( p ) - { - start = p; - p = p->next; - while ( p != start ) - { - n = p->next; - delete p; - p = n; - } - - delete cycle->items; - } - cycle->items = NULL; - cycle->next_item = NULL; -} - -static char com_token[ 1500 ]; - -/* -============== -COM_Parse - -Parse a token out of a string -============== -*/ -char *COM_Parse (char *data) -{ - int c; - int len; - - len = 0; - com_token[0] = 0; - - if (!data) - return NULL; - -// skip whitespace -skipwhite: - while ( (c = *data) <= ' ') - { - if (c == 0) - return NULL; // end of file; - data++; - } - -// skip // comments - if (c=='/' && data[1] == '/') - { - while (*data && *data != '\n') - data++; - goto skipwhite; - } - - -// handle quoted strings specially - if (c == '\"') - { - data++; - while (1) - { - c = *data++; - if (c=='\"' || !c) - { - com_token[len] = 0; - return data; - } - com_token[len] = c; - len++; - } - } - -// parse single characters - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) - { - com_token[len] = c; - len++; - com_token[len] = 0; - return data+1; - } - -// parse a regular word - do - { - com_token[len] = c; - data++; - len++; - c = *data; - if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c == ',' ) - break; - } while (c>32); - - com_token[len] = 0; - return data; -} - -/* -============== -COM_TokenWaiting - -Returns 1 if additional data is waiting to be processed on this line -============== -*/ -int COM_TokenWaiting( char *buffer ) -{ - char *p; - - p = buffer; - while ( *p && *p!='\n') - { - if ( !isspace( *p ) || isalnum( *p ) ) - return 1; - - p++; - } - - return 0; -} - - - -/* -============== -ReloadMapCycleFile - - -Parses mapcycle.txt file into mapcycle_t structure -============== -*/ -int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) -{ - char szBuffer[ MAX_RULE_BUFFER ]; - char szMap[ 32 ]; - int length; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); - int hasbuffer; - mapcycle_item_s *item, *newlist = NULL, *next; - - if ( pFileList && length ) - { - // the first map name in the file becomes the default - while ( 1 ) - { - hasbuffer = 0; - memset( szBuffer, 0, MAX_RULE_BUFFER ); - - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) <= 0 ) - break; - - strcpy( szMap, com_token ); - - // Any more tokens on this line? - if ( COM_TokenWaiting( pFileList ) ) - { - pFileList = COM_Parse( pFileList ); - if ( strlen( com_token ) > 0 ) - { - hasbuffer = 1; - strcpy( szBuffer, com_token ); - } - } - - // Check map - if ( IS_MAP_VALID( szMap ) ) - { - // Create entry - char *s; - - item = new mapcycle_item_s; - - strcpy( item->mapname, szMap ); - - item->minplayers = 0; - item->maxplayers = 0; - - memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); - - if ( hasbuffer ) - { - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); - if ( s && s[0] ) - { - item->minplayers = atoi( s ); - item->minplayers = max( item->minplayers, 0 ); - item->minplayers = min( item->minplayers, gpGlobals->maxClients ); - } - s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); - if ( s && s[0] ) - { - item->maxplayers = atoi( s ); - item->maxplayers = max( item->maxplayers, 0 ); - item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); - } - - // Remove keys - // - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); - g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); - - strcpy( item->rulebuffer, szBuffer ); - } - - item->next = cycle->items; - cycle->items = item; - } - else - { - ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); - } - - } - - FREE_FILE( aFileList ); - } - - // Fixup circular list pointer - item = cycle->items; - - // Reverse it to get original order - while ( item ) - { - next = item->next; - item->next = newlist; - newlist = item; - item = next; - } - cycle->items = newlist; - item = cycle->items; - - // Didn't parse anything - if ( !item ) - { - return 0; - } - - while ( item->next ) - { - item = item->next; - } - item->next = cycle->items; - - cycle->next_item = item->next; - - return 1; -} - -/* -============== -CountPlayers - -Determine the current # of active players on the server for map cycling logic -============== -*/ -int CountPlayers( void ) -{ - int num = 0; - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pEnt = UTIL_PlayerByIndex( i ); - - if ( pEnt ) - { - num = num + 1; - } - } - - return num; -} - -/* -============== -ExtractCommandString - -Parse commands/key value pairs to issue right after map xxx command is issued on server - level transition -============== -*/ -void ExtractCommandString( char *s, char *szCommand ) -{ - // Now make rules happen - char pkey[512]; - char value[512]; // use two buffers so compares - // work without stomping on each other - char *o; - - if ( *s == '\\' ) - s++; - - while (1) - { - o = pkey; - while ( *s != '\\' ) - { - if ( !*s ) - return; - *o++ = *s++; - } - *o = 0; - s++; - - o = value; - - while (*s != '\\' && *s) - { - if (!*s) - return; - *o++ = *s++; - } - *o = 0; - - strcat( szCommand, pkey ); - if ( strlen( value ) > 0 ) - { - strcat( szCommand, " " ); - strcat( szCommand, value ); - } - strcat( szCommand, "\n" ); - - if (!*s) - return; - s++; - } -} - -/* -============== -ChangeLevel - -Server is changing to a new level, check mapcycle.txt for map name and setup info -============== -*/ -void CHalfLifeMultiplay :: ChangeLevel( void ) -{ - static char szPreviousMapCycleFile[ 256 ]; - static mapcycle_t mapcycle; - - char szNextMap[32]; - char szFirstMapInList[32]; - char szCommands[ 1500 ]; - char szRules[ 1500 ]; - int minplayers = 0, maxplayers = 0; - strcpy( szFirstMapInList, "hldm1" ); // the absolute default level is hldm1 - - int curplayers; - BOOL do_cycle = TRUE; - - // find the map to change to - char *mapcfile = (char*)CVAR_GET_STRING( "mapcyclefile" ); - ASSERT( mapcfile != NULL ); - - szCommands[ 0 ] = '\0'; - szRules[ 0 ] = '\0'; - - curplayers = CountPlayers(); - - // Has the map cycle filename changed? - if ( stricmp( mapcfile, szPreviousMapCycleFile ) ) - { - strcpy( szPreviousMapCycleFile, mapcfile ); - - DestroyMapCycle( &mapcycle ); - - if ( !ReloadMapCycleFile( mapcfile, &mapcycle ) || ( !mapcycle.items ) ) - { - ALERT( at_console, "Unable to load map cycle file %s\n", mapcfile ); - do_cycle = FALSE; - } - } - - if ( do_cycle && mapcycle.items ) - { - BOOL keeplooking = FALSE; - BOOL found = FALSE; - mapcycle_item_s *item; - - // Assume current map - strcpy( szNextMap, STRING(gpGlobals->mapname) ); - strcpy( szFirstMapInList, STRING(gpGlobals->mapname) ); - - // Traverse list - for ( item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next ) - { - keeplooking = FALSE; - - ASSERT( item != NULL ); - - if ( item->minplayers != 0 ) - { - if ( curplayers >= item->minplayers ) - { - found = TRUE; - minplayers = item->minplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( item->maxplayers != 0 ) - { - if ( curplayers <= item->maxplayers ) - { - found = TRUE; - maxplayers = item->maxplayers; - } - else - { - keeplooking = TRUE; - } - } - - if ( keeplooking ) - continue; - - found = TRUE; - break; - } - - if ( !found ) - { - item = mapcycle.next_item; - } - - // Increment next item pointer - mapcycle.next_item = item->next; - - // Perform logic on current item - strcpy( szNextMap, item->mapname ); - - ExtractCommandString( item->rulebuffer, szCommands ); - strcpy( szRules, item->rulebuffer ); - } - - if ( !IS_MAP_VALID(szNextMap) ) - { - strcpy( szNextMap, szFirstMapInList ); - } - - g_fGameOver = TRUE; - - ALERT( at_console, "CHANGE LEVEL: %s\n", szNextMap ); - if ( minplayers || maxplayers ) - { - ALERT( at_console, "PLAYER COUNT: min %i max %i current %i\n", minplayers, maxplayers, curplayers ); - } - if ( strlen( szRules ) > 0 ) - { - ALERT( at_console, "RULES: %s\n", szRules ); - } - - CHANGE_LEVEL( szNextMap, NULL ); - if ( strlen( szCommands ) > 0 ) - { - SERVER_COMMAND( szCommands ); - } -} - -#define MAX_MOTD_CHUNK 60 -#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4) - -void CHalfLifeMultiplay :: SendMOTDToClient( edict_t *client ) -{ - // read from the MOTD.txt file - int length, char_count = 0; - char *pFileList; - char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( (char *)CVAR_GET_STRING( "motdfile" ), &length ); - - // send the server name - MESSAGE_BEGIN( MSG_ONE, gmsgServerName, NULL, client ); - WRITE_STRING( CVAR_GET_STRING("hostname") ); - MESSAGE_END(); - - // Send the message of the day - // read it chunk-by-chunk, and send it in parts - - while ( pFileList && *pFileList && char_count < MAX_MOTD_LENGTH ) - { - char chunk[MAX_MOTD_CHUNK+1]; - - if ( strlen( pFileList ) < MAX_MOTD_CHUNK ) - { - strcpy( chunk, pFileList ); - } - else - { - strncpy( chunk, pFileList, MAX_MOTD_CHUNK ); - chunk[MAX_MOTD_CHUNK] = 0; // strncpy doesn't always append the null terminator - } - - char_count += strlen( chunk ); - if ( char_count < MAX_MOTD_LENGTH ) - pFileList = aFileList + char_count; - else - *pFileList = 0; - - MESSAGE_BEGIN( MSG_ONE, gmsgMOTD, NULL, client ); - WRITE_BYTE( *pFileList ? FALSE : TRUE ); // FALSE means there is still more message to come - WRITE_STRING( chunk ); - MESSAGE_END(); - } - - FREE_FILE( aFileList ); -} - - diff --git a/sdk/dlls/nihilanth.cpp b/sdk/dlls/nihilanth.cpp deleted file mode 100644 index 94de0ff..0000000 --- a/sdk/dlls/nihilanth.cpp +++ /dev/null @@ -1,1850 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "effects.h" - -#define N_SCALE 15 -#define N_SPHERES 20 - -class CNihilanth : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_ALIEN_MILITARY; }; - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector( -16 * N_SCALE, -16 * N_SCALE, -48 * N_SCALE ); - pev->absmax = pev->origin + Vector( 16 * N_SCALE, 16 * N_SCALE, 28 * N_SCALE ); - } - - void HandleAnimEvent( MonsterEvent_t *pEvent ); - - void EXPORT StartupThink( void ); - void EXPORT HuntThink( void ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT NullThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void FloatSequence( void ); - void NextActivity( void ); - - void Flight( void ); - - BOOL AbsorbSphere( void ); - BOOL EmitSphere( void ); - void TargetSphere( USE_TYPE useType, float value ); - CBaseEntity *RandomTargetname( const char *szName ); - void ShootBalls( void ); - void MakeFriend( Vector vecPos ); - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - - void PainSound( void ); - void DeathSound( void ); - - static const char *pAttackSounds[]; // vocalization: play sometimes when he launches an attack - static const char *pBallSounds[]; // the sound of the lightening ball launch - static const char *pShootSounds[]; // grunting vocalization: play sometimes when he launches an attack - static const char *pRechargeSounds[]; // vocalization: play when he recharges - static const char *pLaughSounds[]; // vocalization: play sometimes when hit and still has lots of health - static const char *pPainSounds[]; // vocalization: play sometimes when hit and has much less health and no more chargers - static const char *pDeathSounds[]; // vocalization: play as he dies - - // x_teleattack1.wav the looping sound of the teleport attack ball. - - float m_flForce; - - float m_flNextPainSound; - - Vector m_velocity; - Vector m_avelocity; - - Vector m_vecTarget; - Vector m_posTarget; - - Vector m_vecDesired; - Vector m_posDesired; - - float m_flMinZ; - float m_flMaxZ; - - Vector m_vecGoal; - - float m_flLastSeen; - float m_flPrevSeen; - - int m_irritation; - - int m_iLevel; - int m_iTeleport; - - EHANDLE m_hRecharger; - - EHANDLE m_hSphere[N_SPHERES]; - int m_iActiveSpheres; - - float m_flAdj; - - CSprite *m_pBall; - - char m_szRechargerTarget[64]; - char m_szDrawUse[64]; - char m_szTeleportUse[64]; - char m_szTeleportTouch[64]; - char m_szDeadUse[64]; - char m_szDeadTouch[64]; - - float m_flShootEnd; - float m_flShootTime; - - EHANDLE m_hFriend[3]; -}; - -LINK_ENTITY_TO_CLASS( monster_nihilanth, CNihilanth ); - -TYPEDESCRIPTION CNihilanth::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanth, m_flForce, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flNextPainSound, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_velocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_avelocity, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posTarget, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_vecDesired, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_posDesired, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flMinZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_flMaxZ, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_vecGoal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanth, m_flLastSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flPrevSeen, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_irritation, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_iTeleport, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_hRecharger, FIELD_EHANDLE ), - DEFINE_ARRAY( CNihilanth, m_hSphere, FIELD_EHANDLE, N_SPHERES ), - DEFINE_FIELD( CNihilanth, m_iActiveSpheres, FIELD_INTEGER ), - DEFINE_FIELD( CNihilanth, m_flAdj, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanth, m_pBall, FIELD_CLASSPTR ), - DEFINE_ARRAY( CNihilanth, m_szRechargerTarget, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDrawUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szTeleportTouch, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadUse, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( CNihilanth, m_szDeadTouch, FIELD_CHARACTER, 64 ), - DEFINE_FIELD( CNihilanth, m_flShootEnd, FIELD_TIME ), - DEFINE_FIELD( CNihilanth, m_flShootTime, FIELD_TIME ), - DEFINE_ARRAY( CNihilanth, m_hFriend, FIELD_EHANDLE, 3 ), -}; - -IMPLEMENT_SAVERESTORE( CNihilanth, CBaseMonster ); - -class CNihilanthHVR : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - void Spawn( void ); - void Precache( void ); - - void CircleInit( CBaseEntity *pTarget ); - void AbsorbInit( void ); - void TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ); - void GreenBallInit( void ); - void ZapInit( CBaseEntity *pEnemy ); - - void EXPORT HoverThink( void ); - BOOL CircleTarget( Vector vecTarget ); - void EXPORT DissipateThink( void ); - - void EXPORT ZapThink( void ); - void EXPORT TeleportThink( void ); - void EXPORT TeleportTouch( CBaseEntity *pOther ); - - void EXPORT RemoveTouch( CBaseEntity *pOther ); - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT ZapTouch( CBaseEntity *pOther ); - - CBaseEntity *RandomClassname( const char *szName ); - - // void EXPORT SphereUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void MovetoTarget( Vector vecTarget ); - virtual void Crawl( void ); - - void Zap( void ); - void Teleport( void ); - - float m_flIdealVel; - Vector m_vecIdeal; - CNihilanth *m_pNihilanth; - EHANDLE m_hTouch; - int m_nFrames; -}; - -LINK_ENTITY_TO_CLASS( nihilanth_energy_ball, CNihilanthHVR ); - - -TYPEDESCRIPTION CNihilanthHVR::m_SaveData[] = -{ - DEFINE_FIELD( CNihilanthHVR, m_flIdealVel, FIELD_FLOAT ), - DEFINE_FIELD( CNihilanthHVR, m_vecIdeal, FIELD_VECTOR ), - DEFINE_FIELD( CNihilanthHVR, m_pNihilanth, FIELD_CLASSPTR ), - DEFINE_FIELD( CNihilanthHVR, m_hTouch, FIELD_EHANDLE ), - DEFINE_FIELD( CNihilanthHVR, m_nFrames, FIELD_INTEGER ), -}; - - -IMPLEMENT_SAVERESTORE( CNihilanthHVR, CBaseMonster ); - - -//========================================================= -// Nihilanth, final Boss monster -//========================================================= - -const char *CNihilanth::pAttackSounds[] = -{ - "X/x_attack1.wav", - "X/x_attack2.wav", - "X/x_attack3.wav", -}; - -const char *CNihilanth::pBallSounds[] = -{ - "X/x_ballattack1.wav", -}; - -const char *CNihilanth::pShootSounds[] = -{ - "X/x_shoot1.wav", -}; - -const char *CNihilanth::pRechargeSounds[] = -{ - "X/x_recharge1.wav", - "X/x_recharge2.wav", - "X/x_recharge3.wav", -}; - -const char *CNihilanth::pLaughSounds[] = -{ - "X/x_laugh1.wav", - "X/x_laugh2.wav", -}; - -const char *CNihilanth::pPainSounds[] = -{ - "X/x_pain1.wav", - "X/x_pain2.wav", -}; - -const char *CNihilanth::pDeathSounds[] = -{ - "X/x_die1.wav", -}; - - -void CNihilanth :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(edict(), "models/nihilanth.mdl"); - // UTIL_SetSize(pev, Vector( -300, -300, 0), Vector(300, 300, 512)); - UTIL_SetSize(pev, Vector( -32, -32, 0), Vector(32, 32, 64)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.nihilanthHealth; - pev->view_ofs = Vector( 0, 0, 300 ); - - m_flFieldOfView = -1; // 360 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - - InitBoneControllers(); - - SetThink( &CNihilanth::StartupThink ); - pev->nextthink = gpGlobals->time + 0.1; - - m_vecDesired = Vector( 1, 0, 0 ); - m_posDesired = Vector( pev->origin.x, pev->origin.y, 512 ); - - m_iLevel = 1; - m_iTeleport = 1; - - if (m_szRechargerTarget[0] == '\0') strcpy( m_szRechargerTarget, "n_recharger" ); - if (m_szDrawUse[0] == '\0') strcpy( m_szDrawUse, "n_draw" ); - if (m_szTeleportUse[0] == '\0') strcpy( m_szTeleportUse, "n_leaving" ); - if (m_szTeleportTouch[0] == '\0') strcpy( m_szTeleportTouch, "n_teleport" ); - if (m_szDeadUse[0] == '\0') strcpy( m_szDeadUse, "n_dead" ); - if (m_szDeadTouch[0] == '\0') strcpy( m_szDeadTouch, "n_ending" ); - - // near death - /* - m_iTeleport = 10; - m_iLevel = 10; - m_irritation = 2; - pev->health = 100; - */ -} - - -void CNihilanth::Precache( void ) -{ - PRECACHE_MODEL("models/nihilanth.mdl"); - PRECACHE_MODEL("sprites/lgtning.spr"); - UTIL_PrecacheOther( "nihilanth_energy_ball" ); - UTIL_PrecacheOther( "monster_alien_controller" ); - UTIL_PrecacheOther( "monster_alien_slave" ); - - PRECACHE_SOUND_ARRAY( pAttackSounds ); - PRECACHE_SOUND_ARRAY( pBallSounds ); - PRECACHE_SOUND_ARRAY( pShootSounds ); - PRECACHE_SOUND_ARRAY( pRechargeSounds ); - PRECACHE_SOUND_ARRAY( pLaughSounds ); - PRECACHE_SOUND_ARRAY( pPainSounds ); - PRECACHE_SOUND_ARRAY( pDeathSounds ); - PRECACHE_SOUND("debris/beamstart7.wav"); -} - - - -void CNihilanth :: PainSound( void ) -{ - if (m_flNextPainSound > gpGlobals->time) - return; - - m_flNextPainSound = gpGlobals->time + RANDOM_FLOAT( 2, 5 ); - - if (pev->health > gSkillData.nihilanthHealth / 2) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pLaughSounds ), 1.0, 0.2 ); - } - else if (m_irritation >= 2) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), 1.0, 0.2 ); - } -} - -void CNihilanth :: DeathSound( void ) -{ - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), 1.0, 0.1 ); -} - - -void CNihilanth::NullThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CNihilanth::StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SetThink( &CNihilanth::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - SetUse( &CNihilanth::CommandUse ); -} - - -void CNihilanth::StartupThink( void ) -{ - m_irritation = 0; - m_flAdj = 512; - - CBaseEntity *pEntity; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_min"); - if (pEntity) - m_flMinZ = pEntity->pev->origin.z; - else - m_flMinZ = -4096; - - pEntity = UTIL_FindEntityByTargetname( NULL, "n_max"); - if (pEntity) - m_flMaxZ = pEntity->pev->origin.z; - else - m_flMaxZ = 4096; - - m_hRecharger = this; - for (int i = 0; i < N_SPHERES; i++) - { - EmitSphere( ); - } - m_hRecharger = NULL; - - SetThink( &CNihilanth::HuntThink); - SetUse( &CNihilanth::CommandUse ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CNihilanth :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); -} - -void CNihilanth :: DyingThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - if (pev->deadflag == DEAD_NO) - { - DeathSound( ); - pev->deadflag = DEAD_DYING; - - m_posDesired.z = m_flMaxZ; - } - - if (pev->deadflag == DEAD_DYING) - { - Flight( ); - - if (fabs( pev->origin.z - m_flMaxZ ) < 16) - { - pev->velocity = Vector( 0, 0, 0 ); - FireTargets( m_szDeadUse, this, this, USE_ON, 1.0 ); - pev->deadflag = DEAD_DEAD; - } - } - - if (m_fSequenceFinished) - { - pev->avelocity.y += RANDOM_FLOAT( -100, 100 ); - if (pev->avelocity.y < -100) - pev->avelocity.y = -100; - if (pev->avelocity.y > 100) - pev->avelocity.y = 100; - - pev->sequence = LookupSequence( "die1" ); - } - - if (m_pBall) - { - if (m_pBall->pev->renderamt > 0) - { - m_pBall->pev->renderamt = max( 0, m_pBall->pev->renderamt - 2); - } - else - { - UTIL_Remove( m_pBall ); - m_pBall = NULL; - } - } - - Vector vecDir, vecSrc, vecAngles; - - UTIL_MakeAimVectors( pev->angles ); - int iAttachment = RANDOM_LONG( 1, 4 ); - - do { - vecDir = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 )); - } while (DotProduct( vecDir, vecDir) > 1.0); - - switch( RANDOM_LONG( 1, 4 )) - { - case 1: // head - vecDir.z = fabs( vecDir.z ) * 0.5; - vecDir = vecDir + 2 * gpGlobals->v_up; - break; - case 2: // eyes - if (DotProduct( vecDir, gpGlobals->v_forward ) < 0) - vecDir = vecDir * -1; - - vecDir = vecDir + 2 * gpGlobals->v_forward; - break; - case 3: // left hand - if (DotProduct( vecDir, gpGlobals->v_right ) > 0) - vecDir = vecDir * -1; - vecDir = vecDir - 2 * gpGlobals->v_right; - break; - case 4: // right hand - if (DotProduct( vecDir, gpGlobals->v_right ) < 0) - vecDir = vecDir * -1; - vecDir = vecDir + 2 * gpGlobals->v_right; - break; - } - - GetAttachment( iAttachment - 1, vecSrc, vecAngles ); - - TraceResult tr; - - UTIL_TraceLine( vecSrc, vecSrc + vecDir * 4096, ignore_monsters, ENT(pev), &tr ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() + 0x1000 * iAttachment ); - WRITE_COORD( tr.vecEndPos.x); - WRITE_COORD( tr.vecEndPos.y); - WRITE_COORD( tr.vecEndPos.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 5 ); // life - WRITE_BYTE( 100 ); // width - WRITE_BYTE( 120 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit( ); - - return; -} - - - -void CNihilanth::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( NULL ); - pev->nextthink = gpGlobals->time; - } -} - - - -void CNihilanth :: GibMonster( void ) -{ - // EMIT_SOUND_DYN(edict(), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - - -void CNihilanth :: FloatSequence( void ) -{ - if (m_irritation >= 2) - { - pev->sequence = LookupSequence( "float_open" ); - } - else if (m_avelocity.y > 30) - { - pev->sequence = LookupSequence( "walk_r" ); - } - else if (m_avelocity.y < -30) - { - pev->sequence = LookupSequence( "walk_l" ); - } - else if (m_velocity.z > 30) - { - pev->sequence = LookupSequence( "walk_u" ); - } - else if (m_velocity.z < -30) - { - pev->sequence = LookupSequence( "walk_d" ); - } - else - { - pev->sequence = LookupSequence( "float" ); - } -} - - -void CNihilanth :: ShootBalls( void ) -{ - if (m_flShootEnd > gpGlobals->time) - { - Vector vecHand, vecAngle; - - while (m_flShootTime < m_flShootEnd && m_flShootTime < gpGlobals->time) - { - if (m_hEnemy != 0) - { - Vector vecSrc, vecDir; - CNihilanthHVR *pEntity; - - GetAttachment( 2, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - // vecDir = (m_posTarget - vecSrc).Normalize( ); - vecDir = (m_posTarget - pev->origin).Normalize( ); - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - - GetAttachment( 3, vecHand, vecAngle ); - vecSrc = vecHand + pev->velocity * (m_flShootTime - gpGlobals->time); - // vecDir = (m_posTarget - vecSrc).Normalize( ); - vecDir = (m_posTarget - pev->origin).Normalize( ); - vecSrc = vecSrc + vecDir * (gpGlobals->time - m_flShootTime); - pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = vecDir * 200.0; - pEntity->ZapInit( m_hEnemy ); - } - m_flShootTime += 0.2; - } - } -} - - -void CNihilanth :: MakeFriend( Vector vecStart ) -{ - int i; - - for (i = 0; i < 3; i++) - { - if (m_hFriend[i] != 0 && !m_hFriend[i]->IsAlive()) - { - if (pev->rendermode == kRenderNormal) // don't do it if they are already fading - m_hFriend[i]->MyMonsterPointer()->FadeMonster( ); - m_hFriend[i] = NULL; - } - - if (m_hFriend[i] == 0) - { - if (RANDOM_LONG(0, 1) == 0) - { - int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_AIR ); - if (iNode != NO_NODE) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 32 ), node.m_vecOrigin + Vector( 0, 0, 32 ), dont_ignore_monsters, large_hull, NULL, &tr ); - if (tr.fStartSolid == 0) - m_hFriend[i] = Create("monster_alien_controller", node.m_vecOrigin, pev->angles ); - } - } - else - { - int iNode = WorldGraph.FindNearestNode ( vecStart, bits_NODE_LAND | bits_NODE_WATER ); - if (iNode != NO_NODE) - { - CNode &node = WorldGraph.Node( iNode ); - TraceResult tr; - UTIL_TraceHull( node.m_vecOrigin + Vector( 0, 0, 36 ), node.m_vecOrigin + Vector( 0, 0, 36 ), dont_ignore_monsters, human_hull, NULL, &tr ); - if (tr.fStartSolid == 0) - m_hFriend[i] = Create("monster_alien_slave", node.m_vecOrigin, pev->angles ); - } - } - if (m_hFriend[i] != 0) - { - EMIT_SOUND( m_hFriend[i]->edict(), CHAN_WEAPON, "debris/beamstart7.wav", 1.0, ATTN_NORM ); - } - - return; - } - } -} - - -void CNihilanth :: NextActivity( ) -{ - UTIL_MakeAimVectors( pev->angles ); - - if (m_irritation >= 2) - { - if (m_pBall == NULL) - { - m_pBall = CSprite::SpriteCreate( "sprites/tele1.spr", pev->origin, TRUE ); - if (m_pBall) - { - m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation ); - m_pBall->SetAttachment( edict(), 1 ); - m_pBall->SetScale( 4.0 ); - m_pBall->pev->framerate = 10.0; - m_pBall->TurnOn( ); - } - } - - if (m_pBall) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x1000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 200 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); - } - } - - if ((pev->health < gSkillData.nihilanthHealth / 2 || m_iActiveSpheres < N_SPHERES / 2) && m_hRecharger == 0 && m_iLevel <= 9) - { - char szName[64]; - - CBaseEntity *pEnt = NULL; - CBaseEntity *pRecharger = NULL; - float flDist = 8192; - - sprintf(szName, "%s%d", m_szRechargerTarget, m_iLevel ); - - while ((pEnt = UTIL_FindEntityByTargetname( pEnt, szName )) != NULL) - { - float flLocal = (pEnt->pev->origin - pev->origin).Length(); - if (flLocal < flDist) - { - flDist = flLocal; - pRecharger = pEnt; - } - } - - if (pRecharger) - { - m_hRecharger = pRecharger; - m_posDesired = Vector( pev->origin.x, pev->origin.y, pRecharger->pev->origin.z ); - m_vecDesired = (pRecharger->pev->origin - m_posDesired).Normalize( ); - m_vecDesired.z = 0; - m_vecDesired = m_vecDesired.Normalize(); - } - else - { - m_hRecharger = NULL; - ALERT( at_aiconsole, "nihilanth can't find %s\n", szName ); - m_iLevel++; - if (m_iLevel > 9) - m_irritation = 2; - } - } - - float flDist = (m_posDesired - pev->origin).Length(); - float flDot = DotProduct( m_vecDesired, gpGlobals->v_forward ); - - if (m_hRecharger != 0) - { - // at we at power up yet? - if (flDist < 128.0) - { - int iseq = LookupSequence( "recharge" ); - - if (iseq != pev->sequence) - { - char szText[64]; - - sprintf( szText, "%s%d", m_szDrawUse, m_iLevel ); - FireTargets( szText, this, this, USE_ON, 1.0 ); - - ALERT( at_console, "fireing %s\n", szText ); - } - pev->sequence = LookupSequence( "recharge" ); - } - else - { - FloatSequence( ); - } - return; - } - - if (m_hEnemy != 0 && !m_hEnemy->IsAlive()) - { - m_hEnemy = 0; - } - - if (m_flLastSeen + 15 < gpGlobals->time) - { - m_hEnemy = 0; - } - - if (m_hEnemy == 0) - { - Look( 4096 ); - m_hEnemy = BestVisibleEnemy( ); - } - - if (m_hEnemy != 0 && m_irritation != 0) - { - if (m_flLastSeen + 5 > gpGlobals->time && flDist < 256 && flDot > 0) - { - if (m_irritation >= 2 && pev->health < gSkillData.nihilanthHealth / 2.0) - { - pev->sequence = LookupSequence( "attack1_open" ); - } - else - { - if (RANDOM_LONG(0, 1 ) == 0) - { - pev->sequence = LookupSequence( "attack1" ); // zap - } - else - { - char szText[64]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if (pTrigger != NULL || pTouch != NULL) - { - pev->sequence = LookupSequence( "attack2" ); // teleport - } - else - { - m_iTeleport++; - pev->sequence = LookupSequence( "attack1" ); // zap - } - } - } - return; - } - } - - FloatSequence( ); -} - -void CNihilanth :: HuntThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ShootBalls( ); - - // if dead, force cancelation of current animation - if (pev->health <= 0) - { - SetThink( &CNihilanth::DyingThink ); - m_fSequenceFinished = TRUE; - return; - } - - // ALERT( at_console, "health %.0f\n", pev->health ); - - // if damaged, try to abosorb some spheres - if (pev->health < gSkillData.nihilanthHealth && AbsorbSphere( )) - { - pev->health += gSkillData.nihilanthHealth / N_SPHERES; - } - - // get new sequence - if (m_fSequenceFinished) - { - // if (!m_fSequenceLoops) - pev->frame = 0; - NextActivity( ); - ResetSequenceInfo( ); - pev->framerate = 2.0 - 1.0 * (pev->health / gSkillData.nihilanthHealth); - } - - // look for current enemy - if (m_hEnemy != 0 && m_hRecharger == 0) - { - if (FVisible( m_hEnemy )) - { - if (m_flLastSeen < gpGlobals->time - 5) - m_flPrevSeen = gpGlobals->time; - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->pev->origin; - m_vecTarget = (m_posTarget - pev->origin).Normalize(); - m_vecDesired = m_vecTarget; - m_posDesired = Vector( pev->origin.x, pev->origin.y, m_posTarget.z + m_flAdj ); - } - else - { - m_flAdj = min( m_flAdj + 10, 1000 ); - } - } - - // don't go too high - if (m_posDesired.z > m_flMaxZ) - m_posDesired.z = m_flMaxZ; - - // don't go too low - if (m_posDesired.z < m_flMinZ) - m_posDesired.z = m_flMinZ; - - Flight( ); -} - - - -void CNihilanth :: Flight( void ) -{ - // estimate where I'll be facing in one seconds - UTIL_MakeAimVectors( pev->angles + m_avelocity ); - // Vector vecEst1 = pev->origin + m_velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 ); - // float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right ); - - float flSide = DotProduct( m_vecDesired, gpGlobals->v_right ); - - if (flSide < 0) - { - if (m_avelocity.y < 180) - { - m_avelocity.y += 6; // 9 * (3.0/2.0); - } - } - else - { - if (m_avelocity.y > -180) - { - m_avelocity.y -= 6; // 9 * (3.0/2.0); - } - } - m_avelocity.y *= 0.98; - - // estimate where I'll be in two seconds - Vector vecEst = pev->origin + m_velocity * 2.0 + gpGlobals->v_up * m_flForce * 20; - - // add immediate force - UTIL_MakeAimVectors( pev->angles ); - m_velocity.x += gpGlobals->v_up.x * m_flForce; - m_velocity.y += gpGlobals->v_up.y * m_flForce; - m_velocity.z += gpGlobals->v_up.z * m_flForce; - - - float flSpeed = m_velocity.Length(); - float flDir = DotProduct( Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, 0 ), Vector( m_velocity.x, m_velocity.y, 0 ) ); - if (flDir < 0) - flSpeed = -flSpeed; - - // sideways drag - m_velocity.x = m_velocity.x * (1.0 - fabs( gpGlobals->v_right.x ) * 0.05); - m_velocity.y = m_velocity.y * (1.0 - fabs( gpGlobals->v_right.y ) * 0.05); - m_velocity.z = m_velocity.z * (1.0 - fabs( gpGlobals->v_right.z ) * 0.05); - - // general drag - m_velocity = m_velocity * 0.995; - - // apply power to stay correct height - if (m_flForce < 100 && vecEst.z < m_posDesired.z) - { - m_flForce += 10; - } - else if (m_flForce > -100 && vecEst.z > m_posDesired.z) - { - if (vecEst.z > m_posDesired.z) - m_flForce -= 10; - } - - UTIL_SetOrigin( pev, pev->origin + m_velocity * 0.1 ); - pev->angles = pev->angles + m_avelocity * 0.1; - - // ALERT( at_console, "%5.0f %5.0f : %4.0f : %3.0f : %2.0f\n", m_posDesired.z, pev->origin.z, m_velocity.z, m_avelocity.y, m_flForce ); -} - - -BOOL CNihilanth :: AbsorbSphere( void ) -{ - for (int i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != 0) - { - CNihilanthHVR *pSphere = (CNihilanthHVR *)((CBaseEntity *)m_hSphere[i]); - pSphere->AbsorbInit( ); - m_hSphere[i] = NULL; - m_iActiveSpheres--; - return TRUE; - } - } - return FALSE; -} - - -BOOL CNihilanth :: EmitSphere( void ) -{ - m_iActiveSpheres = 0; - int empty = 0; - - for (int i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != 0) - { - m_iActiveSpheres++; - } - else - { - empty = i; - } - } - - if (m_iActiveSpheres >= N_SPHERES) - return FALSE; - - Vector vecSrc = m_hRecharger->pev->origin; - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->CircleInit( this ); - - m_hSphere[empty] = pEntity; - return TRUE; -} - - -void CNihilanth :: TargetSphere( USE_TYPE useType, float value ) -{ - CBaseMonster *pSphere; - int i; - for (i = 0; i < N_SPHERES; i++) - { - if (m_hSphere[i] != 0) - { - pSphere = m_hSphere[i]->MyMonsterPointer(); - if (pSphere->m_hEnemy == 0) - break; - } - } - if (i == N_SPHERES) - { - return; - } - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - UTIL_SetOrigin( pSphere->pev, vecSrc ); - pSphere->Use( this, this, useType, value ); - pSphere->pev->velocity = m_vecDesired * RANDOM_FLOAT( 50, 100 ) + Vector( RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ), RANDOM_FLOAT( -50, 50 ) ); -} - - - -void CNihilanth :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 1: // shoot - break; - case 2: // zen - if (m_hEnemy != 0) - { - if (RANDOM_LONG(0,4) == 0) - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - break; - case 3: // prayer - if (m_hEnemy != 0) - { - char szText[32]; - - sprintf( szText, "%s%d", m_szTeleportTouch, m_iTeleport ); - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, szText ); - - sprintf( szText, "%s%d", m_szTeleportUse, m_iTeleport ); - CBaseEntity *pTrigger = UTIL_FindEntityByTargetname( NULL, szText ); - - if (pTrigger != NULL || pTouch != NULL) - { - EMIT_SOUND( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAttackSounds ), 1.0, 0.2 ); - - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->TeleportInit( this, m_hEnemy, pTrigger, pTouch ); - } - else - { - m_iTeleport++; // unexpected failure - - EMIT_SOUND( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBallSounds ), 1.0, 0.2 ); - - ALERT( at_aiconsole, "nihilanth can't target %s\n", szText ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x3000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) + 0x4000 ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - m_flShootTime = gpGlobals->time; - m_flShootEnd = gpGlobals->time + 1.0; - } - } - break; - case 4: // get a sphere - { - if (m_hRecharger != 0) - { - if (!EmitSphere( )) - { - m_hRecharger = 0; - } - } - } - break; - case 5: // start up sphere machine - { - EMIT_SOUND( edict(), CHAN_VOICE , RANDOM_SOUND_ARRAY( pRechargeSounds ), 1.0, 0.2 ); - } - break; - case 6: - if (m_hEnemy != 0) - { - Vector vecSrc, vecAngles; - GetAttachment( 2, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = pev->origin - vecSrc; - pEntity->ZapInit( m_hEnemy ); - } - break; - case 7: - /* - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - CNihilanthHVR *pEntity = (CNihilanthHVR *)Create( "nihilanth_energy_ball", vecSrc, pev->angles, edict() ); - pEntity->pev->velocity = Vector ( RANDOM_FLOAT( -0.7, 0.7 ), RANDOM_FLOAT( -0.7, 0.7 ), 1.0 ) * 600.0; - pEntity->GreenBallInit( ); - */ - break; - } -} - - - -void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - switch (useType) - { - case USE_OFF: - { - CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - - if ( pTouch ) - { - if ( m_hEnemy != 0 ) - { - pTouch->Touch( m_hEnemy ); - } - // if the player is using "notarget", the ending sequence won't fire unless we catch it here - else - { - CBaseEntity *pEntity = UTIL_FindEntityByClassname( NULL, "player" ); - if ( pEntity != NULL && pEntity->IsAlive() ) - { - pTouch->Touch( pEntity ); - } - } - } - } - break; - case USE_ON: - if (m_irritation == 0) - { - m_irritation = 1; - } - break; - case USE_SET: - break; - case USE_TOGGLE: - break; - } -} - - -int CNihilanth :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (pevInflictor->owner == edict()) - return 0; - - if (flDamage >= pev->health) - { - pev->health = 1; - if (m_irritation != 3) - return 0; - } - - PainSound( ); - - pev->health -= flDamage; - return 0; -} - - - -void CNihilanth::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if (m_irritation == 3) - m_irritation = 2; - - if (m_irritation == 2 && ptr->iHitgroup == 2 && flDamage > 2) - m_irritation = 3; - - if (m_irritation != 3) - { - Vector vecBlood = (ptr->vecEndPos - pev->origin).Normalize( ); - - UTIL_BloodStream( ptr->vecEndPos, vecBlood, BloodColor(), flDamage + (100 - 100 * (pev->health / gSkillData.nihilanthHealth))); - } - - // SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage * 5.0);// a little surface blood. - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - - - -CBaseEntity *CNihilanth::RandomTargetname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - - - - - - - - - -//========================================================= -// Controller bouncy ball attack -//========================================================= - - - -void CNihilanthHVR :: Spawn( void ) -{ - Precache( ); - - pev->rendermode = kRenderTransAdd; - pev->renderamt = 255; - pev->scale = 3.0; -} - - -void CNihilanthHVR :: Precache( void ) -{ - PRECACHE_MODEL("sprites/flare6.spr"); - PRECACHE_MODEL("sprites/nhth1.spr"); - PRECACHE_MODEL("sprites/exit1.spr"); - PRECACHE_MODEL("sprites/tele1.spr"); - PRECACHE_MODEL("sprites/animglow01.spr"); - PRECACHE_MODEL("sprites/xspark4.spr"); - PRECACHE_MODEL("sprites/muzzleflash3.spr"); - PRECACHE_SOUND("debris/zap4.wav"); - PRECACHE_SOUND("weapons/electro4.wav"); - PRECACHE_SOUND("x/x_teleattack1.wav"); -} - - - -void CNihilanthHVR :: CircleInit( CBaseEntity *pTarget ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; - - // SET_MODEL(edict(), "sprites/flare6.spr"); - // pev->scale = 3.0; - // SET_MODEL(edict(), "sprites/xspark4.spr"); - SET_MODEL(edict(), "sprites/muzzleflash3.spr"); - pev->rendercolor.x = 255; - pev->rendercolor.y = 224; - pev->rendercolor.z = 192; - pev->scale = 2.0; - m_nFrames = 1; - pev->renderamt = 255; - - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CNihilanthHVR::HoverThink ); - SetTouch( &CNihilanthHVR::BounceTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - m_hTargetEnt = pTarget; -} - - -CBaseEntity *CNihilanthHVR::RandomClassname( const char *szName ) -{ - int total = 0; - - CBaseEntity *pEntity = NULL; - CBaseEntity *pNewEntity = NULL; - while ((pNewEntity = UTIL_FindEntityByClassname( pNewEntity, szName )) != NULL) - { - total++; - if (RANDOM_LONG(0,total-1) < 1) - pEntity = pNewEntity; - } - return pEntity; -} - -void CNihilanthHVR :: HoverThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (m_hTargetEnt != 0) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 16 * N_SCALE ) ); - } - else - { - UTIL_Remove( this ); - } - - - if (RANDOM_LONG( 0, 99 ) < 5) - { -/* - CBaseEntity *pOther = RandomClassname( STRING(pev->classname) ); - - if (pOther && pOther != this) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( pOther->entindex() ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); - } -*/ -/* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 10 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -*/ - } - - pev->frame = ((int)pev->frame + 1) % m_nFrames; -} - - - - -void CNihilanthHVR :: ZapInit( CBaseEntity *pEnemy ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(edict(), "sprites/nhth1.spr"); - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 2.0; - - pev->velocity = (pEnemy->pev->origin - pev->origin).Normalize() * 200; - - m_hEnemy = pEnemy; - SetThink( &CNihilanthHVR::ZapThink ); - SetTouch( &CNihilanthHVR::ZapTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "debris/zap4.wav", 1, ATTN_NORM, 0, 100 ); -} - -void CNihilanthHVR :: ZapThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.05; - - // check world boundaries - if (m_hEnemy == 0 || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - if (pev->velocity.Length() < 2000) - { - pev->velocity = pev->velocity * 1.2; - } - - - // MovetoTarget( m_hEnemy->Center( ) ); - - if ((m_hEnemy->Center() - pev->origin).Length() < 256) - { - TraceResult tr; - - UTIL_TraceLine( pev->origin, m_hEnemy->Center(), dont_ignore_monsters, edict(), &tr ); - - CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit); - if (pEntity != NULL && pEntity->pev->takedamage) - { - ClearMultiDamage( ); - pEntity->TraceAttack( pev, gSkillData.nihilanthZap, pev->velocity, &tr, DMG_SHOCK ); - ApplyMultiDamage( pev, pev ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( tr.vecEndPos.x ); - WRITE_COORD( tr.vecEndPos.y ); - WRITE_COORD( tr.vecEndPos.z ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 20 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 196 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); - - UTIL_EmitAmbientSound( edict(), tr.vecEndPos, "weapons/electro4.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) ); - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; - return; - } - - pev->frame = (int)(pev->frame + 1) % 11; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 128 ); // radius - WRITE_BYTE( 128 ); // R - WRITE_BYTE( 128 ); // G - WRITE_BYTE( 255 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 128 ); // decay - MESSAGE_END(); - - // Crawl( ); -} - - -void CNihilanthHVR::ZapTouch( CBaseEntity *pOther ) -{ - UTIL_EmitAmbientSound( edict(), pev->origin, "weapons/electro4.wav", 1.0, ATTN_NORM, 0, RANDOM_LONG( 90, 95 ) ); - - RadiusDamage( pev, pev, 50, CLASS_NONE, DMG_SHOCK ); - pev->velocity = pev->velocity * 0; - - /* - for (int i = 0; i < 10; i++) - { - Crawl( ); - } - */ - - SetTouch( NULL ); - UTIL_Remove( this ); - pev->nextthink = gpGlobals->time + 0.2; -} - - - -void CNihilanthHVR :: TeleportInit( CNihilanth *pOwner, CBaseEntity *pEnemy, CBaseEntity *pTarget, CBaseEntity *pTouch ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->velocity.z *= 0.2; - - SET_MODEL(edict(), "sprites/exit1.spr"); - - m_pNihilanth = pOwner; - m_hEnemy = pEnemy; - m_hTargetEnt = pTarget; - m_hTouch = pTouch; - - SetThink( &CNihilanthHVR::TeleportThink ); - SetTouch( &CNihilanthHVR::TeleportTouch ); - pev->nextthink = gpGlobals->time + 0.1; - - EMIT_SOUND_DYN( edict(), CHAN_WEAPON, "x/x_teleattack1.wav", 1, 0.2, 0, 100 ); -} - - -void CNihilanthHVR :: GreenBallInit( ) -{ - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - pev->rendercolor.x = 255; - pev->rendercolor.y = 255; - pev->rendercolor.z = 255; - pev->scale = 1.0; - - SET_MODEL(edict(), "sprites/exit1.spr"); - - SetTouch( &CNihilanthHVR::RemoveTouch ); -} - - -void CNihilanthHVR :: TeleportThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - // check world boundaries - if (m_hEnemy == 0 || !m_hEnemy->IsAlive() || pev->origin.x < -4096 || pev->origin.x > 4096 || pev->origin.y < -4096 || pev->origin.y > 4096 || pev->origin.z < -4096 || pev->origin.z > 4096) - { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - return; - } - - if ((m_hEnemy->Center() - pev->origin).Length() < 128) - { - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); - - if (m_hTargetEnt != 0) - m_hTargetEnt->Use( m_hEnemy, m_hEnemy, USE_ON, 1.0 ); - - if ( m_hTouch != 0 && m_hEnemy != 0 ) - m_hTouch->Touch( m_hEnemy ); - } - else - { - MovetoTarget( m_hEnemy->Center( ) ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( 256 ); // radius - WRITE_BYTE( 0 ); // R - WRITE_BYTE( 255 ); // G - WRITE_BYTE( 0 ); // B - WRITE_BYTE( 10 ); // life * 10 - WRITE_COORD( 256 ); // decay - MESSAGE_END(); - - pev->frame = (int)(pev->frame + 1) % 20; -} - - -void CNihilanthHVR :: AbsorbInit( void ) -{ - SetThink( &CNihilanthHVR::DissipateThink ); - pev->renderamt = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTS ); - WRITE_SHORT( this->entindex() ); - WRITE_SHORT( m_hTargetEnt->entindex() + 0x1000 ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framestart - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 50 ); // life - WRITE_BYTE( 80 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 30 ); // speed - MESSAGE_END(); -} - -void CNihilanthHVR::TeleportTouch( CBaseEntity *pOther ) -{ - CBaseEntity *pEnemy = m_hEnemy; - - if (pOther == pEnemy) - { - if (m_hTargetEnt != 0) - m_hTargetEnt->Use( pEnemy, pEnemy, USE_ON, 1.0 ); - - if (m_hTouch != 0 && pEnemy != NULL ) - m_hTouch->Touch( pEnemy ); - } - else - { - m_pNihilanth->MakeFriend( pev->origin ); - } - - SetTouch( NULL ); - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - - -void CNihilanthHVR :: DissipateThink( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->scale > 5.0) - UTIL_Remove( this ); - - pev->renderamt -= 2; - pev->scale += 0.1; - - if (m_hTargetEnt != 0) - { - CircleTarget( m_hTargetEnt->pev->origin + Vector( 0, 0, 4096 ) ); - } - else - { - UTIL_Remove( this ); - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_ELIGHT ); - WRITE_SHORT( entindex( ) ); // entity, attachment - WRITE_COORD( pev->origin.x ); // origin - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_COORD( pev->renderamt ); // radius - WRITE_BYTE( 255 ); // R - WRITE_BYTE( 192 ); // G - WRITE_BYTE( 64 ); // B - WRITE_BYTE( 2 ); // life * 10 - WRITE_COORD( 0 ); // decay - MESSAGE_END(); -} - - -BOOL CNihilanthHVR :: CircleTarget( Vector vecTarget ) -{ - BOOL fClose = FALSE; - - Vector vecDest = vecTarget; - Vector vecEst = pev->origin + pev->velocity * 0.5; - Vector vecSrc = pev->origin; - vecDest.z = 0; - vecEst.z = 0; - vecSrc.z = 0; - float d1 = (vecDest - vecSrc).Length() - 24 * N_SCALE; - float d2 = (vecDest - vecEst).Length() - 24 * N_SCALE; - - if (m_vecIdeal == Vector( 0, 0, 0 )) - { - m_vecIdeal = pev->velocity; - } - - if (d1 < 0 && d2 <= d1) - { - // ALERT( at_console, "too close\n"); - m_vecIdeal = m_vecIdeal - (vecDest - vecSrc).Normalize() * 50; - } - else if (d1 > 0 && d2 >= d1) - { - // ALERT( at_console, "too far\n"); - m_vecIdeal = m_vecIdeal + (vecDest - vecSrc).Normalize() * 50; - } - pev->avelocity.z = d1 * 20; - - if (d1 < 32) - { - fClose = TRUE; - } - - m_vecIdeal = m_vecIdeal + Vector( RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 ), RANDOM_FLOAT( -2, 2 )); - m_vecIdeal = Vector( m_vecIdeal.x, m_vecIdeal.y, 0 ).Normalize( ) * 200 - /* + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 32 */ - + Vector( 0, 0, m_vecIdeal.z ); - // m_vecIdeal = m_vecIdeal + Vector( -m_vecIdeal.y, m_vecIdeal.x, 0 ).Normalize( ) * 2; - - // move up/down - d1 = vecTarget.z - pev->origin.z; - if (d1 > 0 && m_vecIdeal.z < 200) - m_vecIdeal.z += 20; - else if (d1 < 0 && m_vecIdeal.z > -200) - m_vecIdeal.z -= 20; - - pev->velocity = m_vecIdeal; - - // ALERT( at_console, "%.0f %.0f %.0f\n", m_vecIdeal.x, m_vecIdeal.y, m_vecIdeal.z ); - return fClose; -} - - -void CNihilanthHVR :: MovetoTarget( Vector vecTarget ) -{ - if (m_vecIdeal == Vector( 0, 0, 0 )) - { - m_vecIdeal = pev->velocity; - } - - // accelerate - float flSpeed = m_vecIdeal.Length(); - if (flSpeed > 300) - { - m_vecIdeal = m_vecIdeal.Normalize( ) * 300; - } - m_vecIdeal = m_vecIdeal + (vecTarget - pev->origin).Normalize() * 300; - pev->velocity = m_vecIdeal; -} - - - - -void CNihilanthHVR :: Crawl( void ) -{ - - Vector vecAim = Vector( RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ), RANDOM_FLOAT( -1, 1 ) ).Normalize( ); - Vector vecPnt = pev->origin + pev->velocity * 0.2 + vecAim * 128; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMENTPOINT ); - WRITE_SHORT( entindex() ); - WRITE_COORD( vecPnt.x); - WRITE_COORD( vecPnt.y); - WRITE_COORD( vecPnt.z); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // frame start - WRITE_BYTE( 10 ); // framerate - WRITE_BYTE( 3 ); // life - WRITE_BYTE( 20 ); // width - WRITE_BYTE( 80 ); // noise - WRITE_BYTE( 64 ); // r, g, b - WRITE_BYTE( 128 ); // r, g, b - WRITE_BYTE( 255); // r, g, b - WRITE_BYTE( 255 ); // brightness - WRITE_BYTE( 10 ); // speed - MESSAGE_END(); -} - - -void CNihilanthHVR::RemoveTouch( CBaseEntity *pOther ) -{ - STOP_SOUND(edict(), CHAN_WEAPON, "x/x_teleattack1.wav" ); - UTIL_Remove( this ); -} - -void CNihilanthHVR::BounceTouch( CBaseEntity *pOther ) -{ - Vector vecDir = m_vecIdeal.Normalize( ); - - TraceResult tr = UTIL_GetGlobalTrace( ); - - float n = -DotProduct(tr.vecPlaneNormal, vecDir); - - vecDir = 2.0 * tr.vecPlaneNormal * n + vecDir; - - m_vecIdeal = vecDir * m_vecIdeal.Length(); -} - - - -#endif diff --git a/sdk/dlls/nodes.cpp b/sdk/dlls/nodes.cpp deleted file mode 100644 index 35cb44b..0000000 --- a/sdk/dlls/nodes.cpp +++ /dev/null @@ -1,3657 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// nodes.cpp - AI node tree stuff. -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "nodes.h" -#include "animation.h" -#include "doors.h" - -#if !defined ( _WIN32 ) -#include -#include -#include -#include // mkdir -#endif - -#define HULL_STEP_SIZE 16// how far the test hull moves on each step -#define NODE_HEIGHT 8 // how high to lift nodes off the ground after we drop them all (make stair/ramp mapping easier) - -// to help eliminate node clutter by level designers, this is used to cap how many other nodes -// any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()". -#define MAX_NODE_INITIAL_LINKS 128 -#define MAX_NODES 1024 - -extern DLL_GLOBAL edict_t *g_pBodyQueueHead; - -Vector VecBModelOrigin( entvars_t* pevBModel ); - -CGraph WorldGraph; - -LINK_ENTITY_TO_CLASS( info_node, CNodeEnt ); -LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt ); -#ifdef _LINUX -#include -#define CreateDirectory(p, n) mkdir(p, 0777) -#endif -//========================================================= -// CGraph - InitGraph - prepares the graph for use. Frees any -// memory currently in use by the world graph, NULLs -// all pointers, and zeros the node count. -//========================================================= -void CGraph :: InitGraph( void) -{ - - // Make the graph unavailable - // - m_fGraphPresent = FALSE; - m_fGraphPointersSet = FALSE; - m_fRoutingComplete = FALSE; - - // Free the link pool - // - if ( m_pLinkPool ) - { - free ( m_pLinkPool ); - m_pLinkPool = NULL; - } - - // Free the node info - // - if ( m_pNodes ) - { - free ( m_pNodes ); - m_pNodes = NULL; - } - - if ( m_di ) - { - free ( m_di ); - m_di = NULL; - } - - // Free the routing info. - // - if ( m_pRouteInfo ) - { - free ( m_pRouteInfo ); - m_pRouteInfo = NULL; - } - - if (m_pHashLinks) - { - free(m_pHashLinks); - m_pHashLinks = NULL; - } - - // Zero node and link counts - // - m_cNodes = 0; - m_cLinks = 0; - m_nRouteInfo = 0; - - m_iLastActiveIdleSearch = 0; - m_iLastCoverSearch = 0; -} - -//========================================================= -// CGraph - AllocNodes - temporary function that mallocs a -// reasonable number of nodes so we can build the path which -// will be saved to disk. -//========================================================= -int CGraph :: AllocNodes ( void ) -{ -// malloc all of the nodes - WorldGraph.m_pNodes = (CNode *)calloc ( sizeof ( CNode ), MAX_NODES ); - -// could not malloc space for all the nodes! - if ( !WorldGraph.m_pNodes ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", WorldGraph.m_cNodes ); - return FALSE; - } - - return TRUE; -} - -//========================================================= -// CGraph - LinkEntForLink - sometimes the ent that blocks -// a path is a usable door, in which case the monster just -// needs to face the door and fire it. In other cases, the -// monster needs to operate a button or lever to get the -// door to open. This function will return a pointer to the -// button if the monster needs to hit a button to open the -// door, or returns a pointer to the door if the monster -// need only use the door. -// -// pNode is the node the monster will be standing on when it -// will need to stop and trigger the ent. -//========================================================= -entvars_t* CGraph :: LinkEntForLink ( CLink *pLink, CNode *pNode ) -{ - edict_t *pentSearch; - edict_t *pentTrigger; - entvars_t *pevTrigger; - entvars_t *pevLinkEnt; - TraceResult tr; - - pevLinkEnt = pLink->m_pLinkEnt; - if ( !pevLinkEnt ) - return NULL; - - pentSearch = NULL;// start search at the top of the ent list. - - if ( FClassnameIs ( pevLinkEnt, "func_door" ) || FClassnameIs ( pevLinkEnt, "func_door_rotating" ) ) - { - - ///!!!UNDONE - check for TOGGLE or STAY open doors here. If a door is in the way, and is - // TOGGLE or STAY OPEN, even monsters that can't open doors can go that way. - - if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) - {// door is use only, so the door is all the monster has to worry about - return pevLinkEnt; - } - - while ( 1 ) - { - pentTrigger = FIND_ENTITY_BY_TARGET ( pentSearch, STRING( pevLinkEnt->targetname ) );// find the button or trigger - - if ( FNullEnt( pentTrigger ) ) - {// no trigger found - - // right now this is a problem among auto-open doors, or any door that opens through the use - // of a trigger brush. Trigger brushes have no models, and don't show up in searches. Just allow - // monsters to open these sorts of doors for now. - return pevLinkEnt; - } - - pentSearch = pentTrigger; - pevTrigger = VARS( pentTrigger ); - - if ( FClassnameIs(pevTrigger, "func_button") || FClassnameIs(pevTrigger, "func_rot_button" ) ) - {// only buttons are handled right now. - - // trace from the node to the trigger, make sure it's one we can see from the node. - // !!!HACKHACK Use bodyqueue here cause there are no ents we really wish to ignore! - UTIL_TraceLine ( pNode->m_vecOrigin, VecBModelOrigin( pevTrigger ), ignore_monsters, g_pBodyQueueHead, &tr ); - - - if ( VARS(tr.pHit) == pevTrigger ) - {// good to go! - return VARS( tr.pHit ); - } - } - } - } - else - { - ALERT ( at_aiconsole, "Unsupported PathEnt:\n'%s'\n", STRING ( pevLinkEnt->classname ) ); - return NULL; - } -} - -//========================================================= -// CGraph - HandleLinkEnt - a brush ent is between two -// nodes that would otherwise be able to see each other. -// Given the monster's capability, determine whether -// or not the monster can go this way. -//========================================================= -int CGraph :: HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ) -{ - CBaseEntity *pDoor; - TraceResult tr; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - if ( FNullEnt ( pevLinkEnt ) ) - { - ALERT ( at_aiconsole, "dead path ent!\n" ); - return TRUE; - } - -// func_door - if ( FClassnameIs( pevLinkEnt, "func_door" ) || FClassnameIs( pevLinkEnt, "func_door_rotating" ) ) - {// ent is a door. - - pDoor = ( CBaseEntity::Instance( pevLinkEnt ) ); - - if ( ( pevLinkEnt->spawnflags & SF_DOOR_USE_ONLY ) ) - {// door is use only. - - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - {// let monster right through if he can open doors - return TRUE; - } - else - { - // monster should try for it if the door is open and looks as if it will stay that way - if ( pDoor->GetToggleState()== TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) - { - return TRUE; - } - - return FALSE; - } - } - else - {// door must be opened with a button or trigger field. - - // monster should try for it if the door is open and looks as if it will stay that way - if ( pDoor->GetToggleState() == TS_AT_TOP && ( pevLinkEnt->spawnflags & SF_DOOR_NO_AUTO_RETURN ) ) - { - return TRUE; - } - if ( ( afCapMask & bits_CAP_OPEN_DOORS ) ) - { - if ( !( pevLinkEnt->spawnflags & SF_DOOR_NOMONSTERS ) || queryType == NODEGRAPH_STATIC ) - return TRUE; - } - - return FALSE; - } - } -// func_breakable - else if ( FClassnameIs( pevLinkEnt, "func_breakable" ) && queryType == NODEGRAPH_STATIC ) - { - return TRUE; - } - else - { - ALERT ( at_aiconsole, "Unhandled Ent in Path %s\n", STRING( pevLinkEnt->classname ) ); - return FALSE; - } - - return FALSE; -} - -#if 0 -//========================================================= -// FindNearestLink - finds the connection (line) nearest -// the given point. Returns FALSE if fails, or TRUE if it -// has stuffed the index into the nearest link pool connection -// into the passed int pointer, and a BOOL telling whether or -// not the point is along the line into the passed BOOL pointer. -//========================================================= -int CGraph :: FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ) -{ - int i, j;// loops - - int iNearestLink;// index into the link pool, this is the nearest node at any time. - float flMinDist;// the distance of of the nearest case so far - float flDistToLine;// the distance of the current test case - - BOOL fCurrentAlongLine; - BOOL fSuccess; - - //float flConstant;// line constant - Vector vecSpot1, vecSpot2; - Vector2D vec2Spot1, vec2Spot2, vec2TestPoint; - Vector2D vec2Normal;// line normal - Vector2D vec2Line; - - TraceResult tr; - - iNearestLink = -1;// prepare for failure - fSuccess = FALSE; - - flMinDist = 9999;// anything will be closer than this - -// go through all of the nodes, and each node's connections - int cSkip = 0;// how many links proper pairing allowed us to skip - int cChecked = 0;// how many links were checked - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - vecSpot1 = m_pNodes[ i ].m_vecOrigin; - - if ( m_pNodes[ i ].m_cNumLinks <= 0 ) - {// this shouldn't happen! - ALERT ( at_aiconsole, "**Node %d has no links\n", i ); - continue; - } - - for ( j = 0 ; j < m_pNodes[ i ].m_cNumLinks ; j++ ) - { - /* - !!!This optimization only works when the node graph consists of properly linked pairs. - if ( INodeLink ( i, j ) <= i ) - { - // since we're going through the nodes in order, don't check - // any connections whose second node is lower in the list - // than the node we're currently working with. This eliminates - // redundant checks. - cSkip++; - continue; - } - */ - - vecSpot2 = PNodeLink ( i, j )->m_vecOrigin; - - // these values need a little attention now and then, or sometimes ramps cause trouble. - if ( fabs ( vecSpot1.z - vecTestPoint.z ) > 48 && fabs ( vecSpot2.z - vecTestPoint.z ) > 48 ) - { - // if both endpoints of the line are 32 units or more above or below the monster, - // the monster won't be able to get to them, so we do a bit of trivial rejection here. - // this may change if monsters are allowed to jump down. - // - // !!!LATER: some kind of clever X/Y hashing should be used here, too - continue; - } - -// now we have two endpoints for a line segment that we've not already checked. -// since all lines that make it this far are within -/+ 32 units of the test point's -// Z Plane, we can get away with doing the point->line check in 2d. - - cChecked++; - - vec2Spot1 = vecSpot1.Make2D(); - vec2Spot2 = vecSpot2.Make2D(); - vec2TestPoint = vecTestPoint.Make2D(); - - // get the line normal. - vec2Line = ( vec2Spot1 - vec2Spot2 ).Normalize(); - vec2Normal.x = -vec2Line.y; - vec2Normal.y = vec2Line.x; - - if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot1 ) ) > 0 ) - {// point outside of line - flDistToLine = ( vec2TestPoint - vec2Spot1 ).Length(); - fCurrentAlongLine = FALSE; - } - else if ( DotProduct ( vec2Line, ( vec2TestPoint - vec2Spot2 ) ) < 0 ) - {// point outside of line - flDistToLine = ( vec2TestPoint - vec2Spot2 ).Length(); - fCurrentAlongLine = FALSE; - } - else - {// point inside line - flDistToLine = fabs( DotProduct ( vec2TestPoint - vec2Spot2, vec2Normal ) ); - fCurrentAlongLine = TRUE; - } - - if ( flDistToLine < flMinDist ) - {// just found a line nearer than any other so far - - UTIL_TraceLine ( vecTestPoint, SourceNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); - - if ( tr.flFraction != 1.0 ) - {// crap. can't see the first node of this link, try to see the other - - UTIL_TraceLine ( vecTestPoint, DestNode( i, j ).m_vecOrigin, ignore_monsters, g_pBodyQueueHead, &tr ); - if ( tr.flFraction != 1.0 ) - {// can't use this link, cause can't see either node! - continue; - } - - } - - fSuccess = TRUE;// we know there will be something to return. - flMinDist = flDistToLine; - iNearestLink = m_pNodes [ i ].m_iFirstLink + j; - *piNearestLink = m_pNodes[ i ].m_iFirstLink + j; - *pfAlongLine = fCurrentAlongLine; - } - } - } - -/* - if ( fSuccess ) - { - WRITE_BYTE(MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE(MSG_BROADCAST, TE_SHOWLINE); - - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.x ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.y ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iSrcNode ].m_vecOrigin.z + NODE_HEIGHT); - - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.x ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.y ); - WRITE_COORD(MSG_BROADCAST, m_pNodes[ m_pLinkPool[ iNearestLink ].m_iDestNode ].m_vecOrigin.z + NODE_HEIGHT); - } -*/ - - ALERT ( at_aiconsole, "%d Checked\n", cChecked ); - return fSuccess; -} - -#endif - -int CGraph::HullIndex( const CBaseEntity *pEntity ) -{ - if ( pEntity->pev->movetype == MOVETYPE_FLY) - return NODE_FLY_HULL; - - if ( pEntity->pev->mins == Vector( -12, -12, 0 ) ) - return NODE_SMALL_HULL; - else if ( pEntity->pev->mins == VEC_HUMAN_HULL_MIN ) - return NODE_HUMAN_HULL; - else if ( pEntity->pev->mins == Vector ( -32, -32, 0 ) ) - return NODE_LARGE_HULL; - -// ALERT ( at_aiconsole, "Unknown Hull Mins!\n" ); - return NODE_HUMAN_HULL; -} - - -int CGraph::NodeType( const CBaseEntity *pEntity ) -{ - if ( pEntity->pev->movetype == MOVETYPE_FLY) - { - if (pEntity->pev->waterlevel != 0) - { - return bits_NODE_WATER; - } - else - { - return bits_NODE_AIR; - } - } - return bits_NODE_LAND; -} - - -// Sum up graph weights on the path from iStart to iDest to determine path length -float CGraph::PathLength( int iStart, int iDest, int iHull, int afCapMask ) -{ - float distance = 0; - int iNext; - - int iMaxLoop = m_cNodes; - - int iCurrentNode = iStart; - int iCap = CapIndex( afCapMask ); - - while (iCurrentNode != iDest) - { - if (iMaxLoop-- <= 0) - { - ALERT( at_console, "Route Failure\n" ); - return 0; - } - - iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) - { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); - return 0; - } - - int iLink; - HashSearch(iCurrentNode, iNext, iLink); - if (iLink < 0) - { - ALERT(at_console, "HashLinks is broken from %d to %d.\n", iCurrentNode, iDest); - return 0; - } - CLink &link = Link(iLink); - distance += link.m_flWeight; - - iCurrentNode = iNext; - } - - return distance; -} - - -// Parse the routing table at iCurrentNode for the next node on the shortest path to iDest -int CGraph::NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ) -{ - int iNext = iCurrentNode; - int nCount = iDest+1; - char *pRoute = m_pRouteInfo + m_pNodes[ iCurrentNode ].m_pNextBestNode[iHull][iCap]; - - // Until we decode the next best node - // - while (nCount > 0) - { - char ch = *pRoute++; - //ALERT(at_aiconsole, "C(%d)", ch); - if (ch < 0) - { - // Sequence phrase - // - ch = -ch; - if (nCount <= ch) - { - iNext = iDest; - nCount = 0; - //ALERT(at_aiconsole, "SEQ: iNext/iDest=%d\n", iNext); - } - else - { - //ALERT(at_aiconsole, "SEQ: nCount + ch (%d + %d)\n", nCount, ch); - nCount = nCount - ch; - } - } - else - { - //ALERT(at_aiconsole, "C(%d)", *pRoute); - - // Repeat phrase - // - if (nCount <= ch+1) - { - iNext = iCurrentNode + *pRoute; - if (iNext >= m_cNodes) iNext -= m_cNodes; - else if (iNext < 0) iNext += m_cNodes; - nCount = 0; - //ALERT(at_aiconsole, "REP: iNext=%d\n", iNext); - } - else - { - //ALERT(at_aiconsole, "REP: nCount - ch+1 (%d - %d+1)\n", nCount, ch); - nCount = nCount - ch - 1; - } - pRoute++; - } - } - - return iNext; -} - - -//========================================================= -// CGraph - FindShortestPath -// -// accepts a capability mask (afCapMask), and will only -// find a path usable by a monster with those capabilities -// returns the number of nodes copied into supplied array -//========================================================= -int CGraph :: FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask) -{ - int iVisitNode; - int iCurrentNode; - int iNumPathNodes; - int iHullMask = 0; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - if ( iStart < 0 || iStart > m_cNodes ) - {// The start node is bad? - ALERT ( at_aiconsole, "Can't build a path, iStart is %d!\n", iStart ); - return FALSE; - } - - if (iStart == iDest) - { - piPath[0] = iStart; - piPath[1] = iDest; - return 2; - } - - // Is routing information present. - // - if (m_fRoutingComplete) - { - int iCap = CapIndex( afCapMask ); - - iNumPathNodes = 0; - piPath[iNumPathNodes++] = iStart; - iCurrentNode = iStart; - int iNext; - - //ALERT(at_aiconsole, "GOAL: %d to %d\n", iStart, iDest); - - // Until we arrive at the destination - // - while (iCurrentNode != iDest) - { - iNext = NextNodeInRoute( iCurrentNode, iDest, iHull, iCap ); - if (iCurrentNode == iNext) - { - //ALERT(at_aiconsole, "SVD: Can't get there from here..\n"); - return 0; - break; - } - if (iNumPathNodes >= MAX_PATH_SIZE) - { - //ALERT(at_aiconsole, "SVD: Don't return the entire path.\n"); - break; - } - piPath[iNumPathNodes++] = iNext; - iCurrentNode = iNext; - } - //ALERT( at_aiconsole, "SVD: Path with %d nodes.\n", iNumPathNodes); - } - else - { - CQueuePriority queue; - - switch( iHull ) - { - case NODE_SMALL_HULL: - iHullMask = bits_LINK_SMALL_HULL; - break; - case NODE_HUMAN_HULL: - iHullMask = bits_LINK_HUMAN_HULL; - break; - case NODE_LARGE_HULL: - iHullMask = bits_LINK_LARGE_HULL; - break; - case NODE_FLY_HULL: - iHullMask = bits_LINK_FLY_HULL; - break; - } - - // Mark all the nodes as unvisited. - // - int i; - for ( i = 0; i < m_cNodes; i++) - { - m_pNodes[ i ].m_flClosestSoFar = -1.0; - } - - m_pNodes[ iStart ].m_flClosestSoFar = 0.0; - m_pNodes[ iStart ].m_iPreviousNode = iStart;// tag this as the origin node - queue.Insert( iStart, 0.0 );// insert start node - - while ( !queue.Empty() ) - { - // now pull a node out of the queue - float flCurrentDistance; - iCurrentNode = queue.Remove(flCurrentDistance); - - // For straight-line weights, the following Shortcut works. For arbitrary weights, - // it doesn't. - // - if (iCurrentNode == iDest) break; - - CNode *pCurrentNode = &m_pNodes[ iCurrentNode ]; - - for ( i = 0 ; i < pCurrentNode->m_cNumLinks ; i++ ) - {// run through all of this node's neighbors - - iVisitNode = INodeLink ( iCurrentNode, i ); - if ( ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo & iHullMask ) != iHullMask ) - {// monster is too large to walk this connection - //ALERT ( at_aiconsole, "fat ass %d/%d\n",m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_afLinkInfo, iMonsterHull ); - continue; - } - // check the connection from the current node to the node we're about to mark visited and push into the queue - if ( m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt != NULL ) - {// there's a brush ent in the way! Don't mark this node or put it into the queue unless the monster can negotiate it - - if ( !HandleLinkEnt ( iCurrentNode, m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i ].m_pLinkEnt, afCapMask, NODEGRAPH_STATIC ) ) - {// monster should not try to go this way. - continue; - } - } - float flOurDistance = flCurrentDistance + m_pLinkPool[ m_pNodes[ iCurrentNode ].m_iFirstLink + i].m_flWeight; - if ( m_pNodes[ iVisitNode ].m_flClosestSoFar < -0.5 - || flOurDistance < m_pNodes[ iVisitNode ].m_flClosestSoFar - 0.001 ) - { - m_pNodes[iVisitNode].m_flClosestSoFar = flOurDistance; - m_pNodes[iVisitNode].m_iPreviousNode = iCurrentNode; - - queue.Insert ( iVisitNode, flOurDistance ); - } - } - } - if ( m_pNodes[iDest].m_flClosestSoFar < -0.5 ) - {// Destination is unreachable, no path found. - return 0; - } - - // the queue is not empty - - // now we must walk backwards through the m_iPreviousNode field, and count how many connections there are in the path - iCurrentNode = iDest; - iNumPathNodes = 1;// count the dest - - while ( iCurrentNode != iStart ) - { - iNumPathNodes++; - iCurrentNode = m_pNodes[ iCurrentNode ].m_iPreviousNode; - } - - iCurrentNode = iDest; - for ( i = iNumPathNodes - 1 ; i >= 0 ; i-- ) - { - piPath[ i ] = iCurrentNode; - iCurrentNode = m_pNodes [ iCurrentNode ].m_iPreviousNode; - } - } - -#if 0 - - if (m_fRoutingComplete) - { - // This will draw the entire path that was generated for the monster. - - for ( int i = 0 ; i < iNumPathNodes - 1 ; i++ ) - { - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ piPath[ i ] ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ piPath[ i + 1 ] ].m_vecOrigin.z + NODE_HEIGHT ); - MESSAGE_END(); - } - } - -#endif -#if 0 // MAZE map - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ 4 ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ 9 ].m_vecOrigin.z + NODE_HEIGHT ); - MESSAGE_END(); -#endif - - return iNumPathNodes; -} - -inline ULONG Hash(void *p, int len) -{ - CRC32_t ulCrc; - CRC32_INIT(&ulCrc); - CRC32_PROCESS_BUFFER(&ulCrc, p, len); - return CRC32_FINAL(ulCrc); -} - -void inline CalcBounds(int &Lower, int &Upper, int Goal, int Best) -{ - int Temp = 2*Goal - Best; - if (Best > Goal) - { - Lower = max(0, Temp); - Upper = Best; - } - else - { - Upper = min(255, Temp); - Lower = Best; - } -} - -// Convert from [-8192,8192] to [0, 255] -// -inline int CALC_RANGE(int x, int lower, int upper) -{ - return NUM_RANGES*(x-lower)/((upper-lower+1)); -} - - -void inline UpdateRange(int &minValue, int &maxValue, int Goal, int Best) -{ - int Lower, Upper; - CalcBounds(Lower, Upper, Goal, Best); - if (Upper < maxValue) maxValue = Upper; - if (minValue < Lower) minValue = Lower; -} - -void CGraph :: CheckNode(Vector vecOrigin, int iNode) -{ - // Have we already seen this point before?. - // - if (m_di[iNode].m_CheckedEvent == m_CheckedCounter) return; - m_di[iNode].m_CheckedEvent = m_CheckedCounter; - - float flDist = ( vecOrigin - m_pNodes[ iNode ].m_vecOriginPeek ).Length(); - - if ( flDist < m_flShortest ) - { - TraceResult tr; - - // make sure that vecOrigin can trace to this node! - UTIL_TraceLine ( vecOrigin, m_pNodes[ iNode ].m_vecOriginPeek, ignore_monsters, 0, &tr ); - - if ( tr.flFraction == 1.0 ) - { - m_iNearest = iNode; - m_flShortest = flDist; - - UpdateRange(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[iNode].m_Region[0]); - UpdateRange(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[iNode].m_Region[1]); - UpdateRange(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[iNode].m_Region[2]); - - // From maxCircle, calculate maximum bounds box. All points must be - // simultaneously inside all bounds of the box. - // - m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); - m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); - m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); - m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); - m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); - m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]); - } - } -} - -//========================================================= -// CGraph - FindNearestNode - returns the index of the node nearest -// the given vector -1 is failure (couldn't find a valid -// near node ) -//========================================================= -int CGraph :: FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ) -{ - return FindNearestNode( vecOrigin, NodeType( pEntity ) ); -} - -int CGraph :: FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ) -{ - int i; - TraceResult tr; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return -1; - } - - // Check with the cache - // - ULONG iHash = (CACHE_SIZE-1) & Hash((void *)(const float *)vecOrigin, sizeof(vecOrigin)); - if (m_Cache[iHash].v == vecOrigin) - { - //ALERT(at_aiconsole, "Cache Hit.\n"); - return m_Cache[iHash].n; - } - else - { - //ALERT(at_aiconsole, "Cache Miss.\n"); - } - - // Mark all points as unchecked. - // - m_CheckedCounter++; - if (m_CheckedCounter == 0) - { - for (int i = 0; i < m_cNodes; i++) - { - m_di[i].m_CheckedEvent = 0; - } - m_CheckedCounter++; - } - - m_iNearest = -1; - m_flShortest = 999999.0; // just a big number. - - // If we can find a visible point, then let CalcBounds set the limits, but if - // we have no visible point at all to start with, then don't restrict the limits. - // -#if 1 - m_minX = 0; m_maxX = 255; - m_minY = 0; m_maxY = 255; - m_minZ = 0; m_maxZ = 255; - m_minBoxX = 0; m_maxBoxX = 255; - m_minBoxY = 0; m_maxBoxY = 255; - m_minBoxZ = 0; m_maxBoxZ = 255; -#else - m_minBoxX = CALC_RANGE(vecOrigin.x - flDist, m_RegionMin[0], m_RegionMax[0]); - m_maxBoxX = CALC_RANGE(vecOrigin.x + flDist, m_RegionMin[0], m_RegionMax[0]); - m_minBoxY = CALC_RANGE(vecOrigin.y - flDist, m_RegionMin[1], m_RegionMax[1]); - m_maxBoxY = CALC_RANGE(vecOrigin.y + flDist, m_RegionMin[1], m_RegionMax[1]); - m_minBoxZ = CALC_RANGE(vecOrigin.z - flDist, m_RegionMin[2], m_RegionMax[2]); - m_maxBoxZ = CALC_RANGE(vecOrigin.z + flDist, m_RegionMin[2], m_RegionMax[2]) - CalcBounds(m_minX, m_maxX, CALC_RANGE(vecOrigin.x, m_RegionMin[0], m_RegionMax[0]), m_pNodes[m_iNearest].m_Region[0]); - CalcBounds(m_minY, m_maxY, CALC_RANGE(vecOrigin.y, m_RegionMin[1], m_RegionMax[1]), m_pNodes[m_iNearest].m_Region[1]); - CalcBounds(m_minZ, m_maxZ, CALC_RANGE(vecOrigin.z, m_RegionMin[2], m_RegionMax[2]), m_pNodes[m_iNearest].m_Region[2]); -#endif - - int halfX = (m_minX+m_maxX)/2; - int halfY = (m_minY+m_maxY)/2; - int halfZ = (m_minZ+m_maxZ)/2; - - int j; - - for (i = halfX; i >= m_minX; i--) - { - for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; - - int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; - if (rgY > m_maxBoxY) break; - if (rgY < m_minBoxY) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; - if (rgZ < m_minBoxZ) continue; - if (rgZ > m_maxBoxZ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); - } - } - - for (i = max(m_minY,halfY+1); i <= m_maxY; i++) - { - for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; - if (rgZ > m_maxBoxZ) break; - if (rgZ < m_minBoxZ) continue; - int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; - if (rgX < m_minBoxX) continue; - if (rgX > m_maxBoxX) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); - } - } - - for (i = min(m_maxZ,halfZ); i >= m_minZ; i--) - { - for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; - - int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; - if (rgX > m_maxBoxX) break; - if (rgX < m_minBoxX) continue; - int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; - if (rgY < m_minBoxY) continue; - if (rgY > m_maxBoxY) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); - } - } - - for (i = max(m_minX,halfX+1); i <= m_maxX; i++) - { - for (j = m_RangeStart[0][i]; j <= m_RangeEnd[0][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[0]].m_afNodeInfo & afNodeTypes)) continue; - - int rgY = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[1]; - if (rgY > m_maxBoxY) break; - if (rgY < m_minBoxY) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[0]].m_Region[2]; - if (rgZ < m_minBoxZ) continue; - if (rgZ > m_maxBoxZ) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[0]); - } - } - - for (i = min(m_maxY,halfY); i >= m_minY; i--) - { - for (j = m_RangeStart[1][i]; j <= m_RangeEnd[1][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[1]].m_afNodeInfo & afNodeTypes)) continue; - - int rgZ = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[2]; - if (rgZ > m_maxBoxZ) break; - if (rgZ < m_minBoxZ) continue; - int rgX = m_pNodes[m_di[j].m_SortedBy[1]].m_Region[0]; - if (rgX < m_minBoxX) continue; - if (rgX > m_maxBoxX) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[1]); - } - } - - for (i = max(m_minZ,halfZ+1); i <= m_maxZ; i++) - { - for (j = m_RangeStart[2][i]; j <= m_RangeEnd[2][i]; j++) - { - if (!(m_pNodes[m_di[j].m_SortedBy[2]].m_afNodeInfo & afNodeTypes)) continue; - - int rgX = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[0]; - if (rgX > m_maxBoxX) break; - if (rgX < m_minBoxX) continue; - int rgY = m_pNodes[m_di[j].m_SortedBy[2]].m_Region[1]; - if (rgY < m_minBoxY) continue; - if (rgY > m_maxBoxY) continue; - CheckNode(vecOrigin, m_di[j].m_SortedBy[2]); - } - } - -#if 0 - // Verify our answers. - // - int iNearestCheck = -1; - m_flShortest = 8192;// find nodes within this radius - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - float flDist = ( vecOrigin - m_pNodes[ i ].m_vecOriginPeek ).Length(); - - if ( flDist < m_flShortest ) - { - // make sure that vecOrigin can trace to this node! - UTIL_TraceLine ( vecOrigin, m_pNodes[ i ].m_vecOriginPeek, ignore_monsters, 0, &tr ); - - if ( tr.flFraction == 1.0 ) - { - iNearestCheck = i; - m_flShortest = flDist; - } - } - } - - if (iNearestCheck != m_iNearest) - { - ALERT( at_aiconsole, "NOT closest %d(%f,%f,%f) %d(%f,%f,%f).\n", - iNearestCheck, - m_pNodes[iNearestCheck].m_vecOriginPeek.x, - m_pNodes[iNearestCheck].m_vecOriginPeek.y, - m_pNodes[iNearestCheck].m_vecOriginPeek.z, - m_iNearest, - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.x), - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.y), - (m_iNearest == -1?0.0:m_pNodes[m_iNearest].m_vecOriginPeek.z)); - } - if (m_iNearest == -1) - { - ALERT(at_aiconsole, "All that work for nothing.\n"); - } -#endif - m_Cache[iHash].v = vecOrigin; - m_Cache[iHash].n = m_iNearest; - return m_iNearest; -} - -//========================================================= -// CGraph - ShowNodeConnections - draws a line from the given node -// to all connected nodes -//========================================================= -void CGraph :: ShowNodeConnections ( int iNode ) -{ - Vector vecSpot; - CNode *pNode; - CNode *pLinkNode; - int i; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return; - } - - if ( iNode < 0 ) - { - ALERT( at_aiconsole, "Can't show connections for node %d\n", iNode ); - return; - } - - pNode = &m_pNodes[ iNode ]; - - UTIL_ParticleEffect( pNode->m_vecOrigin, g_vecZero, 255, 20 );// show node position - - if ( pNode->m_cNumLinks <= 0 ) - {// no connections! - ALERT ( at_aiconsole, "**No Connections!\n" ); - } - - for ( i = 0 ; i < pNode->m_cNumLinks ; i++ ) - { - - pLinkNode = &Node( NodeLink( iNode, i).m_iDestNode ); - vecSpot = pLinkNode->m_vecOrigin; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.x ); - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.y ); - WRITE_COORD( m_pNodes[ iNode ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + NODE_HEIGHT ); - MESSAGE_END(); - - } -} - -//========================================================= -// CGraph - LinkVisibleNodes - the first, most basic -// function of node graph creation, this connects every -// node to every other node that it can see. Expects a -// pointer to an empty connection pool and a file pointer -// to write progress to. Returns the total number of initial -// links. -// -// If there's a problem with this process, the index -// of the offending node will be written to piBadNode -//========================================================= -int CGraph :: LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ) -{ - int i,j,z; - edict_t *pTraceEnt; - int cTotalLinks, cLinksThisNode, cMaxInitialLinks; - TraceResult tr; - - // !!!BUGBUG - this function returns 0 if there is a problem in the middle of connecting the graph - // it also returns 0 if none of the nodes in a level can see each other. piBadNode is ALWAYS read - // by BuildNodeGraph() if this function returns a 0, so make sure that it doesn't get some random - // number back. - *piBadNode = 0; - - - if ( m_cNodes <= 0 ) - { - ALERT ( at_aiconsole, "No Nodes!\n" ); - return FALSE; - } - - // if the file pointer is bad, don't blow up, just don't write the - // file. - if ( !file ) - { - ALERT ( at_aiconsole, "**LinkVisibleNodes:\ncan't write to file." ); - } - else - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "LinkVisibleNodes - Initial Connections\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - - cTotalLinks = 0;// start with no connections - - // to keep track of the maximum number of initial links any node had so far. - // this lets us keep an eye on MAX_NODE_INITIAL_LINKS to ensure that we are - // being generous enough. - cMaxInitialLinks = 0; - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - cLinksThisNode = 0;// reset this count for each node. - - if ( file ) - { - fprintf ( file, "Node #%4d:\n\n", i ); - } - - for ( z = 0 ; z < MAX_NODE_INITIAL_LINKS ; z++ ) - {// clear out the important fields in the link pool for this node - pLinkPool [ cTotalLinks + z ].m_iSrcNode = i;// so each link knows which node it originates from - pLinkPool [ cTotalLinks + z ].m_iDestNode = 0; - pLinkPool [ cTotalLinks + z ].m_pLinkEnt = NULL; - } - - m_pNodes [ i ].m_iFirstLink = cTotalLinks; - - // now build a list of every other node that this node can see - for ( j = 0 ; j < m_cNodes ; j++ ) - { - if ( j == i ) - {// don't connect to self! - continue; - } - -#if 0 - - if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_WATER) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_WATER) ) - { - // don't connect water nodes to air nodes or land nodes. It just wouldn't be prudent at this juncture. - continue; - } -#else - if ( (m_pNodes[ i ].m_afNodeInfo & bits_NODE_GROUP_REALM) != (m_pNodes[ j ].m_afNodeInfo & bits_NODE_GROUP_REALM) ) - { - // don't connect air nodes to water nodes to land nodes. It just wouldn't be prudent at this juncture. - continue; - } -#endif - - tr.pHit = NULL;// clear every time so we don't get stuck with last trace's hit ent - pTraceEnt = 0; - - UTIL_TraceLine ( m_pNodes[ i ].m_vecOrigin, - m_pNodes[ j ].m_vecOrigin, - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - - if ( tr.fStartSolid ) - continue; - - if ( tr.flFraction != 1.0 ) - {// trace hit a brush ent, trace backwards to make sure that this ent is the only thing in the way. - - pTraceEnt = tr.pHit;// store the ent that the trace hit, for comparison - - UTIL_TraceLine ( m_pNodes[ j ].m_vecOrigin, - m_pNodes[ i ].m_vecOrigin, - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - -// there is a solid_bsp ent in the way of these two nodes, so we must record several things about in order to keep -// track of it in the pathfinding code, as well as through save and restore of the node graph. ANY data that is manipulated -// as part of the process of adding a LINKENT to a connection here must also be done in CGraph::SetGraphPointers, where reloaded -// graphs are prepared for use. - if ( tr.pHit == pTraceEnt && !FClassnameIs( tr.pHit, "worldspawn" ) ) - { - // get a pointer - pLinkPool [ cTotalLinks ].m_pLinkEnt = VARS( tr.pHit ); - - // record the modelname, so that we can save/load node trees - memcpy( pLinkPool [ cTotalLinks ].m_szLinkEntModelname, STRING( VARS(tr.pHit)->model ), 4 ); - - // set the flag for this ent that indicates that it is attached to the world graph - // if this ent is removed from the world, it must also be removed from the connections - // that it formerly blocked. - if ( !FBitSet( VARS( tr.pHit )->flags, FL_GRAPHED ) ) - { - VARS( tr.pHit )->flags += FL_GRAPHED; - } - } - else - {// even if the ent wasn't there, these nodes couldn't be connected. Skip. - continue; - } - } - - if ( file ) - { - fprintf ( file, "%4d", j ); - - if ( !FNullEnt( pLinkPool[ cTotalLinks ].m_pLinkEnt ) ) - {// record info about the ent in the way, if any. - fprintf ( file, " Entity on connection: %s, name: %s Model: %s", STRING( VARS( pTraceEnt )->classname ), STRING ( VARS( pTraceEnt )->targetname ), STRING ( VARS(tr.pHit)->model ) ); - } - - fprintf ( file, "\n" ); - } - - pLinkPool [ cTotalLinks ].m_iDestNode = j; - cLinksThisNode++; - cTotalLinks++; - - // If we hit this, either a level designer is placing too many nodes in the same area, or - // we need to allow for a larger initial link pool. - if ( cLinksThisNode == MAX_NODE_INITIAL_LINKS ) - { - ALERT ( at_aiconsole, "**LinkVisibleNodes:\nNode %d has NodeLinks > MAX_NODE_INITIAL_LINKS", i ); - fprintf ( file, "** NODE %d HAS NodeLinks > MAX_NODE_INITIAL_LINKS **\n", i ); - *piBadNode = i; - return FALSE; - } - else if ( cTotalLinks > MAX_NODE_INITIAL_LINKS * m_cNodes ) - {// this is paranoia - ALERT ( at_aiconsole, "**LinkVisibleNodes:\nTotalLinks > MAX_NODE_INITIAL_LINKS * NUMNODES" ); - *piBadNode = i; - return FALSE; - } - - if ( cLinksThisNode == 0 ) - { - fprintf ( file, "**NO INITIAL LINKS**\n" ); - } - - // record the connection info in the link pool - WorldGraph.m_pNodes [ i ].m_cNumLinks = cLinksThisNode; - - // keep track of the most initial links ANY node had, so we can figure out - // if we have a large enough default link pool - if ( cLinksThisNode > cMaxInitialLinks ) - { - cMaxInitialLinks = cLinksThisNode; - } - } - - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - } - - fprintf ( file, "\n%4d Total Initial Connections - %4d Maximum connections for a single node.\n", cTotalLinks, cMaxInitialLinks ); - fprintf ( file, "----------------------------------------------------------------------------\n\n\n" ); - - return cTotalLinks; -} - -//========================================================= -// CGraph - RejectInlineLinks - expects a pointer to a link -// pool, and a pointer to and already-open file ( if you -// want status reports written to disk ). RETURNS the number -// of connections that were rejected -//========================================================= -int CGraph :: RejectInlineLinks ( CLink *pLinkPool, FILE *file ) -{ - int i,j,k; - - int cRejectedLinks; - - BOOL fRestartLoop;// have to restart the J loop if we eliminate a link. - - CNode *pSrcNode; - CNode *pCheckNode;// the node we are testing for (one of pSrcNode's connections) - CNode *pTestNode;// the node we are checking against ( also one of pSrcNode's connections) - - float flDistToTestNode, flDistToCheckNode; - - Vector2D vec2DirToTestNode, vec2DirToCheckNode; - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "InLine Rejection:\n" ); - fprintf ( file, "----------------------------------------------------------------------------\n" ); - } - - cRejectedLinks = 0; - - for ( i = 0 ; i < m_cNodes ; i++ ) - { - pSrcNode = &m_pNodes[ i ]; - - if ( file ) - { - fprintf ( file, "Node %3d:\n", i ); - } - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) - { - pCheckNode = &m_pNodes[ pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; - - vec2DirToCheckNode = ( pCheckNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); - flDistToCheckNode = vec2DirToCheckNode.Length(); - vec2DirToCheckNode = vec2DirToCheckNode.Normalize(); - - pLinkPool[ pSrcNode->m_iFirstLink + j ].m_flWeight = flDistToCheckNode; - - fRestartLoop = FALSE; - for ( k = 0 ; k < pSrcNode->m_cNumLinks && !fRestartLoop ; k++ ) - { - if ( k == j ) - {// don't check against same node - continue; - } - - pTestNode = &m_pNodes [ pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode ]; - - vec2DirToTestNode = ( pTestNode->m_vecOrigin - pSrcNode->m_vecOrigin ).Make2D(); - - flDistToTestNode = vec2DirToTestNode.Length(); - vec2DirToTestNode = vec2DirToTestNode.Normalize(); - - if ( DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) >= 0.998 ) - { - // there's a chance that TestNode intersects the line to CheckNode. If so, we should disconnect the link to CheckNode. - if ( flDistToTestNode < flDistToCheckNode ) - { - if ( file ) - { - fprintf ( file, "REJECTED NODE %3d through Node %3d, Dot = %8f\n", pLinkPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode, pLinkPool[ pSrcNode->m_iFirstLink + k ].m_iDestNode, DotProduct ( vec2DirToCheckNode, vec2DirToTestNode ) ); - } - - pLinkPool[ pSrcNode->m_iFirstLink + j ] = pLinkPool[ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - pSrcNode->m_cNumLinks--; - j--; - - cRejectedLinks++;// keeping track of how many links are cut, so that we can return that value. - - fRestartLoop = TRUE; - } - } - } - } - - if ( file ) - { - fprintf ( file, "----------------------------------------------------------------------------\n\n" ); - } - } - - return cRejectedLinks; -} - -//========================================================= -// TestHull is a modelless clip hull that verifies reachable -// nodes by walking from every node to each of it's connections -//========================================================= -class CTestHull : public CBaseMonster -{ - -public: - void Spawn( entvars_t *pevMasterNode ); - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void EXPORT CallBuildNodeGraph ( void ); - void BuildNodeGraph ( void ); - void EXPORT ShowBadNode ( void ); - void EXPORT DropDelay ( void ); - void EXPORT PathFind ( void ); - - Vector vecBadNodeOrigin; -}; - -LINK_ENTITY_TO_CLASS( testhull, CTestHull ); - -//========================================================= -// CTestHull::Spawn -//========================================================= -void CTestHull :: Spawn( entvars_t *pevMasterNode ) -{ - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 50; - pev->yaw_speed = 8; - - if ( WorldGraph.m_fGraphPresent ) - {// graph loaded from disk, so we don't need the test hull - SetThink ( &CTestHull::SUB_Remove ); - pev->nextthink = gpGlobals->time; - } - else - { - SetThink ( &CTestHull::DropDelay ); - pev->nextthink = gpGlobals->time + 1; - } - - // Make this invisible - // UNDONE: Shouldn't we just use EF_NODRAW? This doesn't need to go to the client. - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; -} - -//========================================================= -// TestHull::DropDelay - spawns TestHull on top of -// the 0th node and drops it to the ground. -//========================================================= -void CTestHull::DropDelay ( void ) -{ -// UTIL_CenterPrintAll( "Node Graph out of Date. Rebuilding..." ); - - UTIL_SetOrigin ( VARS(pev), WorldGraph.m_pNodes[ 0 ].m_vecOrigin ); - - SetThink ( &CTestHull::CallBuildNodeGraph ); - - pev->nextthink = gpGlobals->time + 1; -} - -//========================================================= -// nodes start out as ents in the world. As they are spawned, -// the node info is recorded then the ents are discarded. -//========================================================= -void CNodeEnt :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "hinttype")) - { - m_sHintType = (short)atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - - if (FStrEq(pkvd->szKeyName, "activity")) - { - m_sHintActivity = (short)atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -//========================================================= -//========================================================= -void CNodeEnt :: Spawn( void ) -{ - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT;// always solid_not - - if ( WorldGraph.m_fGraphPresent ) - {// graph loaded from disk, so discard all these node ents as soon as they spawn - REMOVE_ENTITY( edict() ); - return; - } - - if ( WorldGraph.m_cNodes == 0 ) - {// this is the first node to spawn, spawn the test hull entity that builds and walks the node tree - CTestHull *pHull = GetClassPtr((CTestHull *)NULL); - pHull->Spawn( pev ); - } - - if ( WorldGraph.m_cNodes >= MAX_NODES ) - { - ALERT ( at_aiconsole, "cNodes > MAX_NODES\n" ); - return; - } - - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOriginPeek = - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_vecOrigin = pev->origin; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_flHintYaw = pev->angles.y; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintType = m_sHintType; - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_sHintActivity = m_sHintActivity; - - if (FClassnameIs( pev, "info_node_air" )) - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = bits_NODE_AIR; - else - WorldGraph.m_pNodes[ WorldGraph.m_cNodes ].m_afNodeInfo = 0; - - WorldGraph.m_cNodes++; - - REMOVE_ENTITY( edict() ); -} - -//========================================================= -// CTestHull - ShowBadNode - makes a bad node fizzle. When -// there's a problem with node graph generation, the test -// hull will be placed up the bad node's location and will generate -// particles -//========================================================= -void CTestHull :: ShowBadNode( void ) -{ - pev->movetype = MOVETYPE_FLY; - pev->angles.y = pev->angles.y + 4; - - UTIL_MakeVectors ( pev->angles ); - - UTIL_ParticleEffect ( pev->origin, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin - gpGlobals->v_forward * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin + gpGlobals->v_right * 64, g_vecZero, 255, 25 ); - UTIL_ParticleEffect ( pev->origin - gpGlobals->v_right * 64, g_vecZero, 255, 25 ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -extern BOOL gTouchDisabled; -void CTestHull::CallBuildNodeGraph( void ) -{ - // TOUCH HACK -- Don't allow this entity to call anyone's "touch" function - gTouchDisabled = TRUE; - BuildNodeGraph(); - gTouchDisabled = FALSE; - // Undo TOUCH HACK -} - -//========================================================= -// BuildNodeGraph - think function called by the empty walk -// hull that is spawned by the first node to spawn. This -// function links all nodes that can see each other, then -// eliminates all inline links, then uses a monster-sized -// hull that walks between each node and each of its links -// to ensure that a monster can actually fit through the space -//========================================================= -void CTestHull :: BuildNodeGraph( void ) -{ - TraceResult tr; - FILE *file; - - char szNrpFilename [MAX_PATH];// text node report filename - - CLink *pTempPool; // temporary link pool - - CNode *pSrcNode;// node we're currently working with - CNode *pDestNode;// the other node in comparison operations - - BOOL fSkipRemainingHulls;//if smallest hull can't fit, don't check any others - BOOL fPairsValid;// are all links in the graph evenly paired? - - int i, j, hull; - - int iBadNode;// this is the node that caused graph generation to fail - - int cPoolLinks;// number of links in the pool. - - Vector vecDirToCheckNode; - Vector vecDirToTestNode; - Vector vecStepCheckDir; - Vector vecTraceSpot; - Vector vecSpot; - - Vector2D vec2DirToCheckNode; - Vector2D vec2DirToTestNode; - Vector2D vec2StepCheckDir; - Vector2D vec2TraceSpot; - Vector2D vec2Spot; - - float flYaw;// use this stuff to walk the hull between nodes - float flDist; - int step; - - SetThink ( &CTestHull::SUB_Remove );// no matter what happens, the hull gets rid of itself. - pev->nextthink = gpGlobals->time; - -// malloc a swollen temporary connection pool that we trim down after we know exactly how many connections there are. - pTempPool = (CLink *)calloc ( sizeof ( CLink ) , ( WorldGraph.m_cNodes * MAX_NODE_INITIAL_LINKS ) ); - if ( !pTempPool ) - { - ALERT ( at_aiconsole, "**Could not malloc TempPool!\n" ); - return; - } - - - // make sure directories have been made - GET_GAME_DIR( szNrpFilename ); - strcat( szNrpFilename, "/maps" ); - CreateDirectory( szNrpFilename, NULL ); - strcat( szNrpFilename, "/graphs" ); - CreateDirectory( szNrpFilename, NULL ); - - strcat( szNrpFilename, "/" ); - strcat( szNrpFilename, STRING( gpGlobals->mapname ) ); - strcat( szNrpFilename, ".nrp" ); - - file = fopen ( szNrpFilename, "w+" ); - - if ( !file ) - {// file error - ALERT ( at_aiconsole, "Couldn't create %s!\n", szNrpFilename ); - - if ( pTempPool ) - { - free ( pTempPool ); - } - - return; - } - - fprintf( file, "Node Graph Report for map: %s.bsp\n", STRING(gpGlobals->mapname) ); - fprintf ( file, "%d Total Nodes\n\n", WorldGraph.m_cNodes ); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - {// print all node numbers and their locations to the file. - WorldGraph.m_pNodes[ i ].m_cNumLinks = 0; - WorldGraph.m_pNodes[ i ].m_iFirstLink = 0; - memset(WorldGraph.m_pNodes[ i ].m_pNextBestNode, 0, sizeof(WorldGraph.m_pNodes[ i ].m_pNextBestNode)); - - fprintf ( file, "Node# %4d\n", i ); - fprintf ( file, "Location %4d,%4d,%4d\n",(int)WorldGraph.m_pNodes[ i ].m_vecOrigin.x, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.y, (int)WorldGraph.m_pNodes[ i ].m_vecOrigin.z ); - fprintf ( file, "HintType: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintType ); - fprintf ( file, "HintActivity: %4d\n", WorldGraph.m_pNodes[ i ].m_sHintActivity ); - fprintf ( file, "HintYaw: %4f\n", WorldGraph.m_pNodes[ i ].m_flHintYaw ); - fprintf ( file, "-------------------------------------------------------------------------------\n" ); - } - fprintf ( file, "\n\n" ); - - - // Automatically recognize WATER nodes and drop the LAND nodes to the floor. - // - for ( i = 0; i < WorldGraph.m_cNodes; i++) - { - if (WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_AIR) - { - // do nothing - } - else if (UTIL_PointContents(WorldGraph.m_pNodes[ i ].m_vecOrigin) == CONTENTS_WATER) - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_WATER; - } - else - { - WorldGraph.m_pNodes[ i ].m_afNodeInfo |= bits_NODE_LAND; - - // trace to the ground, then pop up 8 units and place node there to make it - // easier for them to connect (think stairs, chairs, and bumps in the floor). - // After the routing is done, push them back down. - // - TraceResult tr; - - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &tr ); - - // This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH - TraceResult trEnt; - UTIL_TraceLine ( WorldGraph.m_pNodes[i].m_vecOrigin, - WorldGraph.m_pNodes[i].m_vecOrigin - Vector ( 0, 0, 384 ), - dont_ignore_monsters, - g_pBodyQueueHead,//!!!HACKHACK no real ent to supply here, using a global we don't care about - &trEnt ); - - - // Did we hit something closer than the floor? - if ( trEnt.flFraction < tr.flFraction ) - { - // If it was a world brush entity, copy the node location - if ( trEnt.pHit && (trEnt.pHit->v.flags & FL_WORLDBRUSH) ) - tr.vecEndPos = trEnt.vecEndPos; - } - - WorldGraph.m_pNodes[i].m_vecOriginPeek.z = - WorldGraph.m_pNodes[i].m_vecOrigin.z = tr.vecEndPos.z + NODE_HEIGHT; - } - } - - cPoolLinks = WorldGraph.LinkVisibleNodes( pTempPool, file, &iBadNode ); - - if ( !cPoolLinks ) - { - ALERT ( at_aiconsole, "**ConnectVisibleNodes FAILED!\n" ); - - SetThink ( &CTestHull::ShowBadNode );// send the hull off to show the offending node. - //pev->solid = SOLID_NOT; - pev->origin = WorldGraph.m_pNodes[ iBadNode ].m_vecOrigin; - - if ( pTempPool ) - { - free ( pTempPool ); - } - - if ( file ) - {// close the file - fclose ( file ); - } - - return; - } - -// send the walkhull to all of this node's connections now. We'll do this here since -// so much of it relies on being able to control the test hull. - fprintf ( file, "----------------------------------------------------------------------------\n" ); - fprintf ( file, "Walk Rejection:\n"); - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - pSrcNode = &WorldGraph.m_pNodes[ i ]; - - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Node %4d:\n\n", i ); - - for ( j = 0 ; j < pSrcNode->m_cNumLinks ; j++ ) - { - // assume that all hulls can walk this link, then eliminate the ones that can't. - pTempPool [ pSrcNode->m_iFirstLink + j ].m_afLinkInfo = bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL | bits_LINK_FLY_HULL; - - - // do a check for each hull size. - - // if we can't fit a tiny hull through a connection, no other hulls with fit either, so we - // should just fall out of the loop. Do so by setting the SkipRemainingHulls flag. - fSkipRemainingHulls = FALSE; - for ( hull = 0 ; hull < MAX_NODE_HULLS; hull++ ) - { - if (fSkipRemainingHulls && (hull == NODE_HUMAN_HULL || hull == NODE_LARGE_HULL)) // skip the remaining walk hulls - continue; - - switch ( hull ) - { - case NODE_SMALL_HULL: - UTIL_SetSize(pev, Vector(-12, -12, 0), Vector(12, 12, 24)); - break; - case NODE_HUMAN_HULL: - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - break; - case NODE_LARGE_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - break; - case NODE_FLY_HULL: - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - // UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - break; - } - - UTIL_SetOrigin ( pev, pSrcNode->m_vecOrigin );// place the hull on the node - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - ALERT ( at_aiconsole, "OFFGROUND!\n" ); - } - - // now build a yaw that points to the dest node, and get the distance. - if ( j < 0 ) - { - ALERT ( at_aiconsole, "**** j = %d ****\n", j ); - if ( pTempPool ) - { - free ( pTempPool ); - } - - if ( file ) - {// close the file - fclose ( file ); - } - return; - } - - pDestNode = &WorldGraph.m_pNodes [ pTempPool[ pSrcNode->m_iFirstLink + j ].m_iDestNode ]; - - vecSpot = pDestNode->m_vecOrigin; - //vecSpot.z = pev->origin.z; - - if (hull < NODE_FLY_HULL) - { - int SaveFlags = pev->flags; - int MoveMode = WALKMOVE_WORLDONLY; - if (pSrcNode->m_afNodeInfo & bits_NODE_WATER) - { - pev->flags |= FL_SWIM; - MoveMode = WALKMOVE_NORMAL; - } - - flYaw = UTIL_VecToYaw ( pDestNode->m_vecOrigin - pev->origin ); - - flDist = ( vecSpot - pev->origin ).Length2D(); - - int fWalkFailed = FALSE; - - // in this loop we take tiny steps from the current node to the nodes that it links to, one at a time. - // pev->angles.y = flYaw; - for ( step = 0 ; step < flDist && !fWalkFailed ; step += HULL_STEP_SIZE ) - { - float stepSize = HULL_STEP_SIZE; - - if ( (step + stepSize) >= (flDist-1) ) - stepSize = (flDist - step) - 1; - - if ( !WALK_MOVE( ENT(pev), flYaw, stepSize, MoveMode ) ) - {// can't take the next step - - fWalkFailed = TRUE; - break; - } - } - - if (!fWalkFailed && (pev->origin - vecSpot).Length() > 64) - { - // ALERT( at_console, "bogus walk\n"); - // we thought we - fWalkFailed = TRUE; - } - - if (fWalkFailed) - { - - //pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - - // now me must eliminate the hull that couldn't walk this connection - switch ( hull ) - { - case NODE_SMALL_HULL: // if this hull can't fit, nothing can, so drop the connection - fprintf ( file, "NODE_SMALL_HULL step %d\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_SMALL_HULL | bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); - fSkipRemainingHulls = TRUE;// don't bother checking larger hulls - break; - case NODE_HUMAN_HULL: - fprintf ( file, "NODE_HUMAN_HULL step %d\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~(bits_LINK_HUMAN_HULL | bits_LINK_LARGE_HULL); - fSkipRemainingHulls = TRUE;// don't bother checking larger hulls - break; - case NODE_LARGE_HULL: - fprintf ( file, "NODE_LARGE_HULL step %d\n", step ); - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_LARGE_HULL; - break; - } - } - pev->flags = SaveFlags; - } - else - { - TraceResult tr; - - UTIL_TraceHull( pSrcNode->m_vecOrigin + Vector( 0, 0, 32 ), pDestNode->m_vecOriginPeek + Vector( 0, 0, 32 ), ignore_monsters, large_hull, ENT( pev ), &tr ); - if (tr.fStartSolid || tr.flFraction < 1.0) - { - pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo &= ~bits_LINK_FLY_HULL; - } - } - } - - if (pTempPool[ pSrcNode->m_iFirstLink + j ].m_afLinkInfo == 0) - { - fprintf ( file, "Rejected Node %3d - Unreachable by ", pTempPool [ pSrcNode->m_iFirstLink + j ].m_iDestNode ); - pTempPool[ pSrcNode->m_iFirstLink + j ] = pTempPool [ pSrcNode->m_iFirstLink + ( pSrcNode->m_cNumLinks - 1 ) ]; - fprintf ( file, "Any Hull\n" ); - - pSrcNode->m_cNumLinks--; - cPoolLinks--;// we just removed a link, so decrement the total number of links in the pool. - j--; - } - - } - } - fprintf ( file, "-------------------------------------------------------------------------------\n\n\n"); - - cPoolLinks -= WorldGraph.RejectInlineLinks ( pTempPool, file ); - -// now malloc a pool just large enough to hold the links that are actually used - WorldGraph.m_pLinkPool = (CLink *) calloc ( sizeof ( CLink ), cPoolLinks ); - - if ( !WorldGraph.m_pLinkPool ) - {// couldn't make the link pool! - ALERT ( at_aiconsole, "Couldn't malloc LinkPool!\n" ); - if ( pTempPool ) - { - free ( pTempPool ); - } - if ( file ) - {// close the file - fclose ( file ); - } - - return; - } - WorldGraph.m_cLinks = cPoolLinks; - -//copy only the used portions of the TempPool into the graph's link pool - int iFinalPoolIndex = 0; - int iOldFirstLink; - - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - iOldFirstLink = WorldGraph.m_pNodes[ i ].m_iFirstLink;// store this, because we have to re-assign it before entering the copy loop - - WorldGraph.m_pNodes[ i ].m_iFirstLink = iFinalPoolIndex; - - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) - { - WorldGraph.m_pLinkPool[ iFinalPoolIndex++ ] = pTempPool[ iOldFirstLink + j ]; - } - } - - - // Node sorting numbers linked nodes close to each other - // - WorldGraph.SortNodes(); - - // This is used for HashSearch - // - WorldGraph.BuildLinkLookups(); - - fPairsValid = TRUE; // assume that the connection pairs are all valid to start - - fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); - fprintf ( file, "Link Pairings:\n"); - -// link integrity check. The idea here is that if Node A links to Node B, node B should -// link to node A. If not, we have a situation that prevents us from using a basic -// optimization in the FindNearestLink function. - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - for ( j = 0 ; j < WorldGraph.m_pNodes[ i ].m_cNumLinks ; j++ ) - { - int iLink; - WorldGraph.HashSearch(WorldGraph.INodeLink(i,j), i, iLink); - if (iLink < 0) - { - fPairsValid = FALSE;// unmatched link pair. - fprintf ( file, "WARNING: Node %3d does not connect back to Node %3d\n", WorldGraph.INodeLink(i, j), i); - } - } - } - - // !!!LATER - if all connections are properly paired, when can enable an optimization in the pathfinding code - // (in the find nearest line function) - if ( fPairsValid ) - { - fprintf ( file, "\nAll Connections are Paired!\n"); - } - -#ifdef _MSC_VER -#define SIZET_FMT "%Iu" -#else -#define SIZET_FMT "%zu" -#endif - - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "\n\n-------------------------------------------------------------------------------\n"); - fprintf ( file, "Total Number of Connections in Pool: %d\n", cPoolLinks ); - fprintf ( file, "-------------------------------------------------------------------------------\n"); - fprintf ( file, "Connection Pool: " SIZET_FMT " bytes\n", sizeof ( CLink ) * cPoolLinks ); - fprintf ( file, "-------------------------------------------------------------------------------\n"); - - - ALERT ( at_aiconsole, "%d Nodes, %d Connections\n", WorldGraph.m_cNodes, cPoolLinks ); - - // This is used for FindNearestNode - // - WorldGraph.BuildRegionTables(); - - - // Push all of the LAND nodes down to the ground now. Leave the water and air nodes alone. - // - for ( i = 0 ; i < WorldGraph.m_cNodes ; i++ ) - { - if ((WorldGraph.m_pNodes[ i ].m_afNodeInfo & bits_NODE_LAND)) - { - WorldGraph.m_pNodes[ i ].m_vecOrigin.z -= NODE_HEIGHT; - } - } - - - if ( pTempPool ) - {// free the temp pool - free ( pTempPool ); - } - - if ( file ) - { - fclose ( file ); - } - - // We now have some graphing capabilities. - // - WorldGraph.m_fGraphPresent = TRUE;//graph is in memory. - WorldGraph.m_fGraphPointersSet = TRUE;// since the graph was generated, the pointers are ready - WorldGraph.m_fRoutingComplete = FALSE; // Optimal routes aren't computed, yet. - - // Compute and compress the routing information. - // - WorldGraph.ComputeStaticRoutingTables(); - -// save the node graph for this level - WorldGraph.FSaveGraph( (char *)STRING( gpGlobals->mapname ) ); - ALERT( at_console, "Done.\n"); -} - - -//========================================================= -// returns a hardcoded path. -//========================================================= -void CTestHull :: PathFind ( void ) -{ - int iPath[ 50 ]; - int iPathSize; - int i; - CNode *pNode, *pNextNode; - - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return; - } - - iPathSize = WorldGraph.FindShortestPath ( iPath, 0, 19, 0, 0 ); // UNDONE use hull constant - - if ( !iPathSize ) - { - ALERT ( at_aiconsole, "No Path!\n" ); - return; - } - - ALERT ( at_aiconsole, "%d\n", iPathSize ); - - pNode = &WorldGraph.m_pNodes[ iPath [ 0 ] ]; - - for ( i = 0 ; i < iPathSize - 1 ; i++ ) - { - - pNextNode = &WorldGraph.m_pNodes[ iPath [ i + 1 ] ]; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SHOWLINE); - - WRITE_COORD( pNode->m_vecOrigin.x ); - WRITE_COORD( pNode->m_vecOrigin.y ); - WRITE_COORD( pNode->m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( pNextNode->m_vecOrigin.x); - WRITE_COORD( pNextNode->m_vecOrigin.y); - WRITE_COORD( pNextNode->m_vecOrigin.z + NODE_HEIGHT); - MESSAGE_END(); - - pNode = pNextNode; - } - -} - - -//========================================================= -// CStack Constructor -//========================================================= -CStack :: CStack( void ) -{ - m_level = 0; -} - -//========================================================= -// pushes a value onto the stack -//========================================================= -void CStack :: Push( int value ) -{ - if ( m_level >= MAX_STACK_NODES ) - { - printf("Error!\n"); - return; - } - m_stack[m_level] = value; - m_level++; -} - -//========================================================= -// pops a value off of the stack -//========================================================= -int CStack :: Pop( void ) -{ - if ( m_level <= 0 ) - return -1; - - m_level--; - return m_stack[ m_level ]; -} - -//========================================================= -// returns the value on the top of the stack -//========================================================= -int CStack :: Top ( void ) -{ - return m_stack[ m_level - 1 ]; -} - -//========================================================= -// copies every element on the stack into an array LIFO -//========================================================= -void CStack :: CopyToArray ( int *piArray ) -{ - int i; - - for ( i = 0 ; i < m_level ; i++ ) - { - piArray[ i ] = m_stack[ i ]; - } -} - -//========================================================= -// CQueue constructor -//========================================================= -CQueue :: CQueue( void ) -{ - m_cSize = 0; - m_head = 0; - m_tail = -1; -} - -//========================================================= -// inserts a value into the queue -//========================================================= -void CQueue :: Insert ( int iValue, float fPriority ) -{ - - if ( Full() ) - { - printf ( "Queue is full!\n" ); - return; - } - - m_tail++; - - if ( m_tail == MAX_STACK_NODES ) - {//wrap around - m_tail = 0; - } - - m_queue[ m_tail ].Id = iValue; - m_queue[ m_tail ].Priority = fPriority; - m_cSize++; -} - -//========================================================= -// removes a value from the queue (FIFO) -//========================================================= -int CQueue :: Remove ( float &fPriority ) -{ - if ( m_head == MAX_STACK_NODES ) - {// wrap - m_head = 0; - } - - m_cSize--; - fPriority = m_queue[ m_head ].Priority; - return m_queue[ m_head++ ].Id; -} - -//========================================================= -// CQueue constructor -//========================================================= -CQueuePriority :: CQueuePriority( void ) -{ - m_cSize = 0; -} - -//========================================================= -// inserts a value into the priority queue -//========================================================= -void CQueuePriority :: Insert( int iValue, float fPriority ) -{ - - if ( Full() ) - { - printf ( "Queue is full!\n" ); - return; - } - - m_heap[ m_cSize ].Priority = fPriority; - m_heap[ m_cSize ].Id = iValue; - m_cSize++; - Heap_SiftUp(); -} - -//========================================================= -// removes the smallest item from the priority queue -// -//========================================================= -int CQueuePriority :: Remove( float &fPriority ) -{ - int iReturn = m_heap[ 0 ].Id; - fPriority = m_heap[ 0 ].Priority; - - m_cSize--; - - m_heap[ 0 ] = m_heap[ m_cSize ]; - - Heap_SiftDown(0); - return iReturn; -} - -#define HEAP_LEFT_CHILD(x) (2*(x)+1) -#define HEAP_RIGHT_CHILD(x) (2*(x)+2) -#define HEAP_PARENT(x) (((x)-1)/2) - -void CQueuePriority::Heap_SiftDown(int iSubRoot) -{ - int parent = iSubRoot; - int child = HEAP_LEFT_CHILD(parent); - - struct tag_HEAP_NODE Ref = m_heap[ parent ]; - - while (child < m_cSize) - { - int rightchild = HEAP_RIGHT_CHILD(parent); - if (rightchild < m_cSize) - { - if ( m_heap[ rightchild ].Priority < m_heap[ child ].Priority ) - { - child = rightchild; - } - } - if ( Ref.Priority <= m_heap[ child ].Priority ) - break; - - m_heap[ parent ] = m_heap[ child ]; - parent = child; - child = HEAP_LEFT_CHILD(parent); - } - m_heap[ parent ] = Ref; -} - -void CQueuePriority::Heap_SiftUp(void) -{ - int child = m_cSize-1; - while (child) - { - int parent = HEAP_PARENT(child); - if ( m_heap[ parent ].Priority <= m_heap[ child ].Priority ) - break; - - struct tag_HEAP_NODE Tmp; - Tmp = m_heap[ child ]; - m_heap[ child ] = m_heap[ parent ]; - m_heap[ parent ] = Tmp; - - child = parent; - } -} - -//========================================================= -// CGraph - FLoadGraph - attempts to load a node graph from disk. -// if the current level is maps/snar.bsp, maps/graphs/snar.nod -// will be loaded. If file cannot be loaded, the node tree -// will be created and saved to disk. -//========================================================= -int CGraph :: FLoadGraph ( char *szMapName ) -{ - char szFilename[MAX_PATH]; - int iVersion; - int length; - byte *aMemFile; - byte *pMemFile; - - // make sure the directories have been made - char szDirName[MAX_PATH]; - GET_GAME_DIR( szDirName ); - strcat( szDirName, "/maps" ); - CreateDirectory( szDirName, NULL ); - strcat( szDirName, "/graphs" ); - CreateDirectory( szDirName, NULL ); - - strcpy ( szFilename, "maps/graphs/" ); - strcat ( szFilename, szMapName ); - strcat( szFilename, ".nod" ); - - pMemFile = aMemFile = LOAD_FILE_FOR_ME(szFilename, &length); - - if ( !aMemFile ) - { - return FALSE; - } - else - { - // Read the graph version number - // - length -= sizeof(int); - if (length < 0) goto ShortFile; - memcpy(&iVersion, pMemFile, sizeof(int)); - pMemFile += sizeof(int); - - if ( iVersion != GRAPH_VERSION ) - { - // This file was written by a different build of the dll! - // - ALERT ( at_aiconsole, "**ERROR** Graph version is %d, expected %d\n",iVersion, GRAPH_VERSION ); - goto ShortFile; - } - - // Read the graph class - // - length -= sizeof(CGraph); - if (length < 0) goto ShortFile; - memcpy(this, pMemFile, sizeof(CGraph)); - pMemFile += sizeof(CGraph); - - // Set the pointers to zero, just in case we run out of memory. - // - m_pNodes = NULL; - m_pLinkPool = NULL; - m_di = NULL; - m_pRouteInfo = NULL; - m_pHashLinks = NULL; - - - // Malloc for the nodes - // - m_pNodes = ( CNode * )calloc ( sizeof ( CNode ), m_cNodes ); - - if ( !m_pNodes ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d nodes!\n", m_cNodes ); - goto NoMemory; - } - - // Read in all the nodes - // - length -= sizeof(CNode) * m_cNodes; - if (length < 0) goto ShortFile; - memcpy(m_pNodes, pMemFile, sizeof(CNode)*m_cNodes); - pMemFile += sizeof(CNode) * m_cNodes; - - - // Malloc for the link pool - // - m_pLinkPool = ( CLink * )calloc ( sizeof ( CLink ), m_cLinks ); - - if ( !m_pLinkPool ) - { - ALERT ( at_aiconsole, "**ERROR**\nCouldn't malloc %d link!\n", m_cLinks ); - goto NoMemory; - } - - // Read in all the links - // - length -= sizeof(CLink)*m_cLinks; - if (length < 0) goto ShortFile; - memcpy(m_pLinkPool, pMemFile, sizeof(CLink)*m_cLinks); - pMemFile += sizeof(CLink)*m_cLinks; - - // Malloc for the sorting info. - // - m_di = (DIST_INFO *)calloc( sizeof(DIST_INFO), m_cNodes ); - if ( !m_di ) - { - ALERT ( at_aiconsole, "***ERROR**\nCouldn't malloc %d entries sorting nodes!\n", m_cNodes ); - goto NoMemory; - } - - // Read it in. - // - length -= sizeof(DIST_INFO)*m_cNodes; - if (length < 0) goto ShortFile; - memcpy(m_di, pMemFile, sizeof(DIST_INFO)*m_cNodes); - pMemFile += sizeof(DIST_INFO)*m_cNodes; - - // Malloc for the routing info. - // - m_fRoutingComplete = FALSE; - m_pRouteInfo = (char *)calloc( sizeof(char), m_nRouteInfo ); - if ( !m_pRouteInfo ) - { - ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d route bytes!\n", m_nRouteInfo ); - goto NoMemory; - } - m_CheckedCounter = 0; - for (int i = 0; i < m_cNodes; i++) - { - m_di[i].m_CheckedEvent = 0; - } - - // Read in the route information. - // - length -= sizeof(char)*m_nRouteInfo; - if (length < 0) goto ShortFile; - memcpy(m_pRouteInfo, pMemFile, sizeof(char)*m_nRouteInfo); - pMemFile += sizeof(char)*m_nRouteInfo; - m_fRoutingComplete = TRUE;; - - // malloc for the hash links - // - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) - { - ALERT ( at_aiconsole, "***ERROR**\nCounldn't malloc %d hash link bytes!\n", m_nHashLinks ); - goto NoMemory; - } - - // Read in the hash link information - // - length -= sizeof(short)*m_nHashLinks; - if (length < 0) goto ShortFile; - memcpy(m_pHashLinks, pMemFile, sizeof(short)*m_nHashLinks); - pMemFile += sizeof(short)*m_nHashLinks; - - // Set the graph present flag, clear the pointers set flag - // - m_fGraphPresent = TRUE; - m_fGraphPointersSet = FALSE; - - FREE_FILE(aMemFile); - - if (length != 0) - { - ALERT ( at_aiconsole, "***WARNING***:Node graph was longer than expected by %d bytes.!\n", length); - } - - return TRUE; - } - -ShortFile: -NoMemory: - FREE_FILE(aMemFile); - return FALSE; -} - -//========================================================= -// CGraph - FSaveGraph - It's not rocket science. -// this WILL overwrite existing files. -//========================================================= -int CGraph :: FSaveGraph ( char *szMapName ) -{ - - int iVersion = GRAPH_VERSION; - char szFilename[MAX_PATH]; - FILE *file; - - if ( !m_fGraphPresent || !m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_aiconsole, "Graph not ready!\n" ); - return FALSE; - } - - // make sure directories have been made - GET_GAME_DIR( szFilename ); - strcat( szFilename, "/maps" ); - CreateDirectory( szFilename, NULL ); - strcat( szFilename, "/graphs" ); - CreateDirectory( szFilename, NULL ); - - strcat( szFilename, "/" ); - strcat( szFilename, szMapName ); - strcat( szFilename, ".nod" ); - - file = fopen ( szFilename, "wb" ); - - ALERT ( at_aiconsole, "Created: %s\n", szFilename ); - - if ( !file ) - {// couldn't create - ALERT ( at_aiconsole, "Couldn't Create: %s\n", szFilename ); - return FALSE; - } - else - { - // write the version - fwrite ( &iVersion, sizeof ( int ), 1, file ); - - // write the CGraph class - fwrite ( this, sizeof ( CGraph ), 1, file ); - - // write the nodes - fwrite ( m_pNodes, sizeof ( CNode ), m_cNodes, file ); - - // write the links - fwrite ( m_pLinkPool, sizeof ( CLink ), m_cLinks, file ); - - fwrite ( m_di, sizeof(DIST_INFO), m_cNodes, file ); - - // Write the route info. - // - if ( m_pRouteInfo && m_nRouteInfo ) - { - fwrite ( m_pRouteInfo, sizeof( char ), m_nRouteInfo, file ); - } - - if (m_pHashLinks && m_nHashLinks) - { - fwrite(m_pHashLinks, sizeof(short), m_nHashLinks, file); - } - fclose ( file ); - return TRUE; - } -} - -//========================================================= -// CGraph - FSetGraphPointers - Takes the modelnames of -// all of the brush ents that block connections in the node -// graph and resolves them into pointers to those entities. -// this is done after loading the graph from disk, whereupon -// the pointers are not valid. -//========================================================= -int CGraph :: FSetGraphPointers ( void ) -{ - int i; - edict_t *pentLinkEnt; - - for ( i = 0 ; i < m_cLinks ; i++ ) - {// go through all of the links - - if ( m_pLinkPool[ i ].m_pLinkEnt != NULL ) - { - char name[5]; - // when graphs are saved, any valid pointers are will be non-zero, signifying that we should - // reset those pointers upon reloading. Any pointers that were NULL when the graph was saved - // will be NULL when reloaded, and will ignored by this function. - - // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) - memcpy( name, m_pLinkPool[ i ].m_szLinkEntModelname, 4 ); - name[4] = 0; - pentLinkEnt = FIND_ENTITY_BY_STRING( NULL, "model", name ); - - if ( FNullEnt ( pentLinkEnt ) ) - { - // the ent isn't around anymore? Either there is a major problem, or it was removed from the world - // ( like a func_breakable that's been destroyed or something ). Make sure that LinkEnt is null. - ALERT ( at_aiconsole, "**Could not find model %s\n", name ); - m_pLinkPool[ i ].m_pLinkEnt = NULL; - } - else - { - m_pLinkPool[ i ].m_pLinkEnt = VARS( pentLinkEnt ); - - if ( !FBitSet( m_pLinkPool[ i ].m_pLinkEnt->flags, FL_GRAPHED ) ) - { - m_pLinkPool[ i ].m_pLinkEnt->flags += FL_GRAPHED; - } - } - } - } - - // the pointers are now set. - m_fGraphPointersSet = TRUE; - return TRUE; -} - -//========================================================= -// CGraph - CheckNODFile - this function checks the date of -// the BSP file that was just loaded and the date of the a -// ssociated .NOD file. If the NOD file is not present, or -// is older than the BSP file, we rebuild it. -// -// returns FALSE if the .NOD file doesn't qualify and needs -// to be rebuilt. -// -// !!!BUGBUG - the file times we get back are 20 hours ahead! -// since this happens consistantly, we can still correctly -// determine which of the 2 files is newer. This needs fixed, -// though. ( I now suspect that we are getting GMT back from -// these functions and must compensate for local time ) (sjb) -//========================================================= -int CGraph :: CheckNODFile ( char *szMapName ) -{ - int retValue; - - char szBspFilename[MAX_PATH]; - char szGraphFilename[MAX_PATH]; - - - strcpy ( szBspFilename, "maps/" ); - strcat ( szBspFilename, szMapName ); - strcat ( szBspFilename, ".bsp" ); - - strcpy ( szGraphFilename, "maps/graphs/" ); - strcat ( szGraphFilename, szMapName ); - strcat ( szGraphFilename, ".nod" ); - - retValue = TRUE; - - int iCompare; - if (COMPARE_FILE_TIME(szBspFilename, szGraphFilename, &iCompare)) - { - if ( iCompare > 0 ) - {// BSP file is newer. - ALERT ( at_aiconsole, ".NOD File will be updated\n\n" ); - retValue = FALSE; - } - } - else - { - retValue = FALSE; - } - - return retValue; -} - -#define ENTRY_STATE_EMPTY -1 - -struct tagNodePair -{ - short iSrc; - short iDest; -}; - -void CGraph::HashInsert(int iSrcNode, int iDestNode, int iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - m_pHashLinks[i] = iKey; -} - -void CGraph::HashSearch(int iSrcNode, int iDestNode, int &iKey) -{ - struct tagNodePair np; - - np.iSrc = iSrcNode; - np.iDest = iDestNode; - CRC32_t dwHash; - CRC32_INIT(&dwHash); - CRC32_PROCESS_BUFFER(&dwHash, &np, sizeof(np)); - dwHash = CRC32_FINAL(dwHash); - - int di = m_HashPrimes[dwHash&15]; - int i = (dwHash >> 4) % m_nHashLinks; - while (m_pHashLinks[i] != ENTRY_STATE_EMPTY) - { - CLink &link = Link(m_pHashLinks[i]); - if (iSrcNode == link.m_iSrcNode && iDestNode == link.m_iDestNode) - { - break; - } - else - { - i += di; - if (i >= m_nHashLinks) i -= m_nHashLinks; - } - } - iKey = m_pHashLinks[i]; -} - -#define NUMBER_OF_PRIMES 177 - -int Primes[NUMBER_OF_PRIMES] = -{ 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, -71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, -157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, -241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, -347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, -439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, -547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, -643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, -751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, -859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, -977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0 }; - -void CGraph::HashChoosePrimes(int TableSize) -{ - int LargestPrime = TableSize/2; - if (LargestPrime > Primes[NUMBER_OF_PRIMES-2]) - { - LargestPrime = Primes[NUMBER_OF_PRIMES-2]; - } - int Spacing = LargestPrime/16; - - // Pick a set primes that are evenly spaced from (0 to LargestPrime) - // We divide this interval into 16 equal sized zones. We want to find - // one prime number that best represents that zone. - // - int iPrime,iZone;; - for (iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing) - { - // Search for a prime number that is less than the target zone - // number given by iZone. - // - int Lower = Primes[0]; - for (int jPrime = 0; Primes[jPrime] != 0; jPrime++) - { - if (jPrime != 0 && TableSize % Primes[jPrime] == 0) continue; - int Upper = Primes[jPrime]; - if (Lower <= iZone && iZone <= Upper) - { - // Choose the closest lower prime number. - // - if (iZone - Lower <= Upper - iZone) - { - m_HashPrimes[iPrime++] = Lower; - } - else - { - m_HashPrimes[iPrime++] = Upper; - } - break; - } - Lower = Upper; - } - } - - // Alternate negative and positive numbers - // - for (iPrime = 0; iPrime < 16; iPrime += 2) - { - m_HashPrimes[iPrime] = TableSize-m_HashPrimes[iPrime]; - } - - // Shuffle the set of primes to reduce correlation with bits in - // hash key. - // - for (iPrime = 0; iPrime < 16-1; iPrime++) - { - int Pick = RANDOM_LONG(0, 15-iPrime); - int Temp = m_HashPrimes[Pick]; - m_HashPrimes[Pick] = m_HashPrimes[15-iPrime]; - m_HashPrimes[15-iPrime] = Temp; - } -} - -// Renumber nodes so that nodes that link together are together. -// -#define UNNUMBERED_NODE -1 -void CGraph::SortNodes(void) -{ - // We are using m_iPreviousNode to be the new node number. - // After assigning new node numbers to everything, we move - // things and patchup the links. - // - int iNodeCnt = 0; - int i; - m_pNodes[0].m_iPreviousNode = iNodeCnt++; - - for (i = 1; i < m_cNodes; i++) - { - m_pNodes[i].m_iPreviousNode = UNNUMBERED_NODE; - } - - for (i = 0; i < m_cNodes; i++) - { - // Run through all of this node's neighbors - // - for (int j = 0 ; j < m_pNodes[i].m_cNumLinks; j++ ) - { - int iDestNode = INodeLink(i, j); - if (m_pNodes[iDestNode].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[iDestNode].m_iPreviousNode = iNodeCnt++; - } - } - } - - // Assign remaining node numbers to unlinked nodes. - // - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_iPreviousNode == UNNUMBERED_NODE) - { - m_pNodes[i].m_iPreviousNode = iNodeCnt++; - } - } - - // Alter links to reflect new node numbers. - // - for (i = 0; i < m_cLinks; i++) - { - m_pLinkPool[i].m_iSrcNode = m_pNodes[m_pLinkPool[i].m_iSrcNode].m_iPreviousNode; - m_pLinkPool[i].m_iDestNode = m_pNodes[m_pLinkPool[i].m_iDestNode].m_iPreviousNode; - } - - // Rearrange nodes to reflect new node numbering. - // - for (i = 0; i < m_cNodes; i++) - { - while (m_pNodes[i].m_iPreviousNode != i) - { - // Move current node off to where it should be, and bring - // that other node back into the current slot. - // - int iDestNode = m_pNodes[i].m_iPreviousNode; - CNode TempNode = m_pNodes[iDestNode]; - m_pNodes[iDestNode] = m_pNodes[i]; - m_pNodes[i] = TempNode; - } - } -} - -void CGraph::BuildLinkLookups(void) -{ - m_nHashLinks = 3*m_cLinks/2 + 3; - - HashChoosePrimes(m_nHashLinks); - m_pHashLinks = (short *)calloc(sizeof(short), m_nHashLinks); - if (!m_pHashLinks) - { - ALERT(at_aiconsole, "Couldn't allocated Link Lookup Table.\n"); - return; - } - int i; - for (i = 0; i < m_nHashLinks; i++) - { - m_pHashLinks[i] = ENTRY_STATE_EMPTY; - } - - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - HashInsert(link.m_iSrcNode, link.m_iDestNode, i); - } -#if 0 - for (i = 0; i < m_cLinks; i++) - { - CLink &link = Link(i); - int iKey; - HashSearch(link.m_iSrcNode, link.m_iDestNode, iKey); - if (iKey != i) - { - ALERT(at_aiconsole, "HashLinks don't match (%d versus %d)\n", i, iKey); - } - } -#endif -} - -void CGraph::BuildRegionTables(void) -{ - if (m_di) free(m_di); - - // Go ahead and setup for range searching the nodes for FindNearestNodes - // - m_di = (DIST_INFO *)calloc(sizeof(DIST_INFO), m_cNodes); - if (!m_di) - { - ALERT(at_aiconsole, "Couldn't allocated node ordering array.\n"); - return; - } - - // Calculate regions for all the nodes. - // - // - int i; - for (i = 0; i < 3; i++) - { - m_RegionMin[i] = 999999999.0; // just a big number out there; - m_RegionMax[i] = -999999999.0; // just a big number out there; - } - for (i = 0; i < m_cNodes; i++) - { - if (m_pNodes[i].m_vecOrigin.x < m_RegionMin[0]) - m_RegionMin[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y < m_RegionMin[1]) - m_RegionMin[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z < m_RegionMin[2]) - m_RegionMin[2] = m_pNodes[i].m_vecOrigin.z; - - if (m_pNodes[i].m_vecOrigin.x > m_RegionMax[0]) - m_RegionMax[0] = m_pNodes[i].m_vecOrigin.x; - if (m_pNodes[i].m_vecOrigin.y > m_RegionMax[1]) - m_RegionMax[1] = m_pNodes[i].m_vecOrigin.y; - if (m_pNodes[i].m_vecOrigin.z > m_RegionMax[2]) - m_RegionMax[2] = m_pNodes[i].m_vecOrigin.z; - } - for (i = 0; i < m_cNodes; i++) - { - m_pNodes[i].m_Region[0] = CALC_RANGE(m_pNodes[i].m_vecOrigin.x, m_RegionMin[0], m_RegionMax[0]); - m_pNodes[i].m_Region[1] = CALC_RANGE(m_pNodes[i].m_vecOrigin.y, m_RegionMin[1], m_RegionMax[1]); - m_pNodes[i].m_Region[2] = CALC_RANGE(m_pNodes[i].m_vecOrigin.z, m_RegionMin[2], m_RegionMax[2]); - } - - for (i = 0; i < 3; i++) - { - int j; - for (j = 0; j < NUM_RANGES; j++) - { - m_RangeStart[i][j] = 255; - m_RangeEnd[i][j] = 0; - } - for (j = 0; j < m_cNodes; j++) - { - m_di[j].m_SortedBy[i] = j; - } - - for (j = 0; j < m_cNodes - 1; j++) - { - int jNode = m_di[j].m_SortedBy[i]; - int jCodeX = m_pNodes[jNode].m_Region[0]; - int jCodeY = m_pNodes[jNode].m_Region[1]; - int jCodeZ = m_pNodes[jNode].m_Region[2]; - int jCode; - switch (i) - { - case 0: - jCode = (jCodeX << 16) + (jCodeY << 8) + jCodeZ; - break; - case 1: - jCode = (jCodeY << 16) + (jCodeZ << 8) + jCodeX; - break; - case 2: - jCode = (jCodeZ << 16) + (jCodeX << 8) + jCodeY; - break; - } - - for (int k = j+1; k < m_cNodes; k++) - { - int kNode = m_di[k].m_SortedBy[i]; - int kCodeX = m_pNodes[kNode].m_Region[0]; - int kCodeY = m_pNodes[kNode].m_Region[1]; - int kCodeZ = m_pNodes[kNode].m_Region[2]; - int kCode; - switch (i) - { - case 0: - kCode = (kCodeX << 16) + (kCodeY << 8) + kCodeZ; - break; - case 1: - kCode = (kCodeY << 16) + (kCodeZ << 8) + kCodeX; - break; - case 2: - kCode = (kCodeZ << 16) + (kCodeX << 8) + kCodeY; - break; - } - - if (kCode < jCode) - { - // Swap j and k entries. - // - int Tmp = m_di[j].m_SortedBy[i]; - m_di[j].m_SortedBy[i] = m_di[k].m_SortedBy[i]; - m_di[k].m_SortedBy[i] = Tmp; - } - } - } - } - - // Generate lookup tables. - // - for (i = 0; i < m_cNodes; i++) - { - int CodeX = m_pNodes[m_di[i].m_SortedBy[0]].m_Region[0]; - int CodeY = m_pNodes[m_di[i].m_SortedBy[1]].m_Region[1]; - int CodeZ = m_pNodes[m_di[i].m_SortedBy[2]].m_Region[2]; - - if (i < m_RangeStart[0][CodeX]) - { - m_RangeStart[0][CodeX] = i; - } - if (i < m_RangeStart[1][CodeY]) - { - m_RangeStart[1][CodeY] = i; - } - if (i < m_RangeStart[2][CodeZ]) - { - m_RangeStart[2][CodeZ] = i; - } - if (m_RangeEnd[0][CodeX] < i) - { - m_RangeEnd[0][CodeX] = i; - } - if (m_RangeEnd[1][CodeY] < i) - { - m_RangeEnd[1][CodeY] = i; - } - if (m_RangeEnd[2][CodeZ] < i) - { - m_RangeEnd[2][CodeZ] = i; - } - } - - // Initialize the cache. - // - memset(m_Cache, 0, sizeof(m_Cache)); -} - -void CGraph :: ComputeStaticRoutingTables( void ) -{ - int nRoutes = m_cNodes*m_cNodes; -#define FROM_TO(x,y) ((x)*m_cNodes+(y)) - short *Routes = new short[nRoutes]; - - int *pMyPath = new int[m_cNodes]; - unsigned short *BestNextNodes = new unsigned short[m_cNodes]; - char *pRoute = new char[m_cNodes*2]; - - - if (Routes && pMyPath && BestNextNodes && pRoute) - { - int nTotalCompressedSize = 0; - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - - // Initialize Routing table to uncalculated. - // - int iFrom; - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - Routes[FROM_TO(iFrom, iTo)] = -1; - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = m_cNodes-1; iTo >= 0; iTo--) - { - if (Routes[FROM_TO(iFrom, iTo)] != -1) continue; - - int cPathSize = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - - // Use the computed path to update the routing table. - // - if (cPathSize > 1) - { - for (int iNode = 0; iNode < cPathSize-1; iNode++) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode+1]; - for (int iNode1 = iNode+1; iNode1 < cPathSize; iNode1++) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#if 0 - // Well, at first glance, this should work, but actually it's safer - // to be told explictly that you can take a series of node in a - // particular direction. Some links don't appear to have links in - // the opposite direction. - // - for (iNode = cPathSize-1; iNode >= 1; iNode--) - { - int iStart = pMyPath[iNode]; - int iNext = pMyPath[iNode-1]; - for (int iNode1 = iNode-1; iNode1 >= 0; iNode1--) - { - int iEnd = pMyPath[iNode1]; - Routes[FROM_TO(iStart, iEnd)] = iNext; - } - } -#endif - } - else - { - Routes[FROM_TO(iFrom, iTo)] = iFrom; - Routes[FROM_TO(iTo, iFrom)] = iTo; - } - } - } - - for (iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - BestNextNodes[iTo] = Routes[FROM_TO(iFrom, iTo)]; - } - - // Compress this node's routing table. - // - int iLastNode = 9999999; // just really big. - int cSequence = 0; - int cRepeats = 0; - int CompressedSize = 0; - char *p = pRoute; - for (int i = 0; i < m_cNodes; i++) - { - BOOL CanRepeat = ((BestNextNodes[i] == iLastNode) && cRepeats < 127); - BOOL CanSequence = (BestNextNodes[i] == i && cSequence < 128); - - if (cRepeats) - { - if (CanRepeat) - { - cRepeats++; - } - else - { - // Emit the repeat phrase. - // - CompressedSize += 2; // (count-1, iLastNode-i) - *p++ = cRepeats - 1; - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - cRepeats = 0; - - if (CanSequence) - { - // Start a sequence. - // - cSequence++; - } - else - { - // Start another repeat. - // - cRepeats++; - } - } - } - else if (cSequence) - { - if (CanSequence) - { - cSequence++; - } - else - { - // It may be advantageous to combine - // a single-entry sequence phrase with the - // next repeat phrase. - // - if (cSequence == 1 && CanRepeat) - { - // Combine with repeat phrase. - // - cRepeats = 2; - cSequence = 0; - } - else - { - // Emit the sequence phrase. - // - CompressedSize += 1; // (-count) - *p++ = -cSequence; - cSequence = 0; - - // Start a repeat sequence. - // - cRepeats++; - } - } - } - else - { - if (CanSequence) - { - // Start a sequence phrase. - // - cSequence++; - } - else - { - // Start a repeat sequence. - // - cRepeats++; - } - } - iLastNode = BestNextNodes[i]; - } - if (cRepeats) - { - // Emit the repeat phrase. - // - CompressedSize += 2; - *p++ = cRepeats - 1; -#if 0 - iLastNode = iFrom + *pRoute; - if (iLastNode >= m_cNodes) iLastNode -= m_cNodes; - else if (iLastNode < 0) iLastNode += m_cNodes; -#endif - int a = iLastNode - iFrom; - int b = iLastNode - iFrom + m_cNodes; - int c = iLastNode - iFrom - m_cNodes; - if (-128 <= a && a <= 127) - { - *p++ = a; - } - else if (-128 <= b && b <= 127) - { - *p++ = b; - } - else if (-128 <= c && c <= 127) - { - *p++ = c; - } - else - { - ALERT( at_aiconsole, "Nodes need sorting (%d,%d)!\n", iLastNode, iFrom); - } - } - if (cSequence) - { - // Emit the Sequence phrase. - // - CompressedSize += 1; - *p++ = -cSequence; - } - - // Go find a place to store this thing and point to it. - // - int nRoute = p - pRoute; - if (m_pRouteInfo) - { - int i; - for (i = 0; i < m_nRouteInfo - nRoute; i++) - { - if (memcmp(m_pRouteInfo + i, pRoute, nRoute) == 0) - { - break; - } - } - if (i < m_nRouteInfo - nRoute) - { - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = i; - } - else - { - char *Tmp = (char *)calloc(sizeof(char), (m_nRouteInfo + nRoute)); - memcpy(Tmp, m_pRouteInfo, m_nRouteInfo); - free(m_pRouteInfo); - m_pRouteInfo = Tmp; - memcpy(m_pRouteInfo + m_nRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = m_nRouteInfo; - m_nRouteInfo += nRoute; - nTotalCompressedSize += CompressedSize; - } - } - else - { - m_nRouteInfo = nRoute; - m_pRouteInfo = (char *)calloc(sizeof(char), nRoute); - memcpy(m_pRouteInfo, pRoute, nRoute); - m_pNodes[ iFrom ].m_pNextBestNode[iHull][iCap] = 0; - nTotalCompressedSize += CompressedSize; - } - } - } - } - ALERT( at_aiconsole, "Size of Routes = %d\n", nTotalCompressedSize); - } - if (Routes) delete Routes; - if (BestNextNodes) delete BestNextNodes; - if (pRoute) delete pRoute; - if (pMyPath) delete pMyPath; - Routes = 0; - BestNextNodes = 0; - pRoute = 0; - pMyPath = 0; - -#if 0 - TestRoutingTables(); -#endif - m_fRoutingComplete = TRUE; -} - -// Test those routing tables. Doesn't really work, yet. -// -void CGraph :: TestRoutingTables( void ) -{ - int *pMyPath = new int[m_cNodes]; - int *pMyPath2 = new int[m_cNodes]; - if (pMyPath && pMyPath2) - { - for (int iHull = 0; iHull < MAX_NODE_HULLS; iHull++) - { - for (int iCap = 0; iCap < 2; iCap++) - { - int iCapMask; - switch (iCap) - { - case 0: - iCapMask = 0; - break; - - case 1: - iCapMask = bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - break; - } - - for (int iFrom = 0; iFrom < m_cNodes; iFrom++) - { - for (int iTo = 0; iTo < m_cNodes; iTo++) - { - m_fRoutingComplete = FALSE; - int cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - int cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - - // Unless we can look at the entire path, we can verify that it's correct. - // - if (cPathSize2 == MAX_PATH_SIZE) continue; - - // Compare distances. - // -#if 1 - float flDistance1 = 0.0; - int i; - for (i = 0; i < cPathSize1-1; i++) - { - // Find the link from pMyPath[i] to pMyPath[i+1] - // - if (pMyPath[i] == pMyPath[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath[i], iLink ); - if (iVisitNode == pMyPath[i+1]) - { - flDistance1 += m_pLinkPool[ m_pNodes[ pMyPath[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - - float flDistance2 = 0.0; - for (i = 0; i < cPathSize2-1; i++) - { - // Find the link from pMyPath2[i] to pMyPath2[i+1] - // - if (pMyPath2[i] == pMyPath2[i+1]) continue; - int iVisitNode; - BOOL bFound = FALSE; - for (int iLink = 0; iLink < m_pNodes[pMyPath2[i]].m_cNumLinks; iLink++) - { - iVisitNode = INodeLink ( pMyPath2[i], iLink ); - if (iVisitNode == pMyPath2[i+1]) - { - flDistance2 += m_pLinkPool[ m_pNodes[ pMyPath2[i] ].m_iFirstLink + iLink].m_flWeight; - bFound = TRUE; - break; - } - } - if (!bFound) - { - ALERT(at_aiconsole, "No link.\n"); - } - } - if (fabs(flDistance1 - flDistance2) > 0.10) - { -#else - if (cPathSize1 != cPathSize2 || memcmp(pMyPath, pMyPath2, sizeof(int)*cPathSize1) != 0) - { -#endif - ALERT(at_aiconsole, "Routing is inconsistent!!!\n"); - ALERT(at_aiconsole, "(%d to %d |%d/%d)1:", iFrom, iTo, iHull, iCap); - for (int i = 0; i < cPathSize1; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath[i]); - } - ALERT(at_aiconsole, "\n(%d to %d |%d/%d)2:", iFrom, iTo, iHull, iCap); - for (int i = 0; i < cPathSize2; i++) - { - ALERT(at_aiconsole, "%d ", pMyPath2[i]); - } - ALERT(at_aiconsole, "\n"); - m_fRoutingComplete = FALSE; - cPathSize1 = FindShortestPath(pMyPath, iFrom, iTo, iHull, iCapMask); - m_fRoutingComplete = TRUE; - cPathSize2 = FindShortestPath(pMyPath2, iFrom, iTo, iHull, iCapMask); - goto EnoughSaid; - } - } - } - } - } - } - -EnoughSaid: - - if (pMyPath) delete pMyPath; - if (pMyPath2) delete pMyPath2; - pMyPath = 0; - pMyPath2 = 0; -} - - - - - - - - - -//========================================================= -// CNodeViewer - Draws a graph of the shorted path from all nodes -// to current location (typically the player). It then draws -// as many connects as it can per frame, trying not to overflow the buffer -//========================================================= -class CNodeViewer : public CBaseEntity -{ -public: - void Spawn( void ); - - int m_iBaseNode; - int m_iDraw; - int m_nVisited; - int m_aFrom[128]; - int m_aTo[128]; - int m_iHull; - int m_afNodeType; - Vector m_vecColor; - - void FindNodeConnections( int iNode ); - void AddNode( int iFrom, int iTo ); - void EXPORT DrawThink( void ); - -}; -LINK_ENTITY_TO_CLASS( node_viewer, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_human, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_fly, CNodeViewer ); -LINK_ENTITY_TO_CLASS( node_viewer_large, CNodeViewer ); - -void CNodeViewer::Spawn( ) -{ - if ( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet ) - {// protect us in the case that the node graph isn't available or built - ALERT ( at_console, "Graph not ready!\n" ); - UTIL_Remove( this ); - return; - } - - - if (FClassnameIs( pev, "node_viewer_fly")) - { - m_iHull = NODE_FLY_HULL; - m_afNodeType = bits_NODE_AIR; - m_vecColor = Vector( 160, 100, 255 ); - } - else if (FClassnameIs( pev, "node_viewer_large")) - { - m_iHull = NODE_LARGE_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 100, 255, 160 ); - } - else - { - m_iHull = NODE_HUMAN_HULL; - m_afNodeType = bits_NODE_LAND | bits_NODE_WATER; - m_vecColor = Vector( 255, 160, 100 ); - } - - - m_iBaseNode = WorldGraph.FindNearestNode ( pev->origin, m_afNodeType ); - - if ( m_iBaseNode < 0 ) - { - ALERT( at_console, "No nearby node\n" ); - return; - } - - m_nVisited = 0; - - ALERT( at_aiconsole, "basenode %d\n", m_iBaseNode ); - - if (WorldGraph.m_cNodes < 128) - { - for (int i = 0; i < WorldGraph.m_cNodes; i++) - { - AddNode( i, WorldGraph.NextNodeInRoute( i, m_iBaseNode, m_iHull, 0 )); - } - } - else - { - // do a depth traversal - FindNodeConnections( m_iBaseNode ); - - int start = 0; - int end; - do { - end = m_nVisited; - // ALERT( at_console, "%d :", m_nVisited ); - for (end = m_nVisited; start < end; start++) - { - FindNodeConnections( m_aFrom[start] ); - FindNodeConnections( m_aTo[start] ); - } - } while (end != m_nVisited); - } - - ALERT( at_aiconsole, "%d nodes\n", m_nVisited ); - - m_iDraw = 0; - SetThink( &CNodeViewer::DrawThink ); - pev->nextthink = gpGlobals->time; -} - - -void CNodeViewer :: FindNodeConnections ( int iNode ) -{ - AddNode( iNode, WorldGraph.NextNodeInRoute( iNode, m_iBaseNode, m_iHull, 0 )); - for ( int i = 0 ; i < WorldGraph.m_pNodes[ iNode ].m_cNumLinks ; i++ ) - { - CLink *pToLink = &WorldGraph.NodeLink( iNode, i); - AddNode( pToLink->m_iDestNode, WorldGraph.NextNodeInRoute( pToLink->m_iDestNode, m_iBaseNode, m_iHull, 0 )); - } -} - -void CNodeViewer::AddNode( int iFrom, int iTo ) -{ - if (m_nVisited >= 128) - { - return; - } - else - { - if (iFrom == iTo) - return; - - for (int i = 0; i < m_nVisited; i++) - { - if (m_aFrom[i] == iFrom && m_aTo[i] == iTo) - return; - if (m_aFrom[i] == iTo && m_aTo[i] == iFrom) - return; - } - m_aFrom[m_nVisited] = iFrom; - m_aTo[m_nVisited] = iTo; - m_nVisited++; - } -} - - -void CNodeViewer :: DrawThink( void ) -{ - pev->nextthink = gpGlobals->time; - - for (int i = 0; i < 10; i++) - { - if (m_iDraw == m_nVisited) - { - UTIL_Remove( this ); - return; - } - - extern short g_sModelIndexLaser; - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BEAMPOINTS ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.x ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.y ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aFrom[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); - - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.x ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.y ); - WRITE_COORD( WorldGraph.m_pNodes[ m_aTo[m_iDraw] ].m_vecOrigin.z + NODE_HEIGHT ); - WRITE_SHORT( g_sModelIndexLaser ); - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 250 ); // life - WRITE_BYTE( 40 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( m_vecColor.x ); // r, g, b - WRITE_BYTE( m_vecColor.y ); // r, g, b - WRITE_BYTE( m_vecColor.z ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - m_iDraw++; - } -} - - diff --git a/sdk/dlls/nodes.h b/sdk/dlls/nodes.h deleted file mode 100644 index 29ffc5c..0000000 --- a/sdk/dlls/nodes.h +++ /dev/null @@ -1,379 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// nodes.h -//========================================================= - -#ifndef NODES_H -#define NODES_H - -//========================================================= -// DEFINE -//========================================================= -#define MAX_STACK_NODES 100 -#define NO_NODE -1 -#define MAX_NODE_HULLS 4 - -#define bits_NODE_LAND ( 1 << 0 ) // Land node, so nudge if necessary. -#define bits_NODE_AIR ( 1 << 1 ) // Air node, don't nudge. -#define bits_NODE_WATER ( 1 << 2 ) // Water node, don't nudge. -#define bits_NODE_GROUP_REALM (bits_NODE_LAND | bits_NODE_AIR | bits_NODE_WATER) - -//========================================================= -// Instance of a node. -//========================================================= -class CNode -{ -public: - Vector m_vecOrigin;// location of this node in space - Vector m_vecOriginPeek; // location of this node (LAND nodes are NODE_HEIGHT higher). - BYTE m_Region[3]; // Which of 256 regions do each of the coordinate belong? - int m_afNodeInfo;// bits that tell us more about this location - - int m_cNumLinks; // how many links this node has - int m_iFirstLink;// index of this node's first link in the link pool. - - // Where to start looking in the compressed routing table (offset into m_pRouteInfo). - // (4 hull sizes -- smallest to largest + fly/swim), and secondly, door capability. - // - int m_pNextBestNode[MAX_NODE_HULLS][2]; - - // Used in finding the shortest path. m_fClosestSoFar is -1 if not visited. - // Then it is the distance to the source. If another path uses this node - // and has a closer distance, then m_iPreviousNode is also updated. - // - float m_flClosestSoFar; // Used in finding the shortest path. - int m_iPreviousNode; - - short m_sHintType;// there is something interesting in the world at this node's position - short m_sHintActivity;// there is something interesting in the world at this node's position - float m_flHintYaw;// monster on this node should face this yaw to face the hint. -}; - -//========================================================= -// CLink - A link between 2 nodes -//========================================================= -#define bits_LINK_SMALL_HULL ( 1 << 0 )// headcrab box can fit through this connection -#define bits_LINK_HUMAN_HULL ( 1 << 1 )// player box can fit through this connection -#define bits_LINK_LARGE_HULL ( 1 << 2 )// big box can fit through this connection -#define bits_LINK_FLY_HULL ( 1 << 3 )// a flying big box can fit through this connection -#define bits_LINK_DISABLED ( 1 << 4 )// link is not valid when the set - -#define NODE_SMALL_HULL 0 -#define NODE_HUMAN_HULL 1 -#define NODE_LARGE_HULL 2 -#define NODE_FLY_HULL 3 - -class CLink -{ -public: - int m_iSrcNode;// the node that 'owns' this link ( keeps us from having to make reverse lookups ) - int m_iDestNode;// the node on the other end of the link. - - entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc) - - // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) - char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore) - - int m_afLinkInfo;// information about this link - float m_flWeight;// length of the link line segment -}; - - -typedef struct -{ - int m_SortedBy[3]; - int m_CheckedEvent; -} DIST_INFO; - -typedef struct -{ - Vector v; - short n; // Nearest node or -1 if no node found. -} CACHE_ENTRY; - -//========================================================= -// CGraph -//========================================================= -#define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. -class CGraph -{ -public: - -// the graph has two flags, and should not be accessed unless both flags are TRUE! - BOOL m_fGraphPresent;// is the graph in memory? - BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set? - BOOL m_fRoutingComplete; // are the optimal routes computed, yet? - - CNode *m_pNodes;// pointer to the memory block that contains all node info - CLink *m_pLinkPool;// big list of all node connections - char *m_pRouteInfo; // compressed routing information the nodes use. - - int m_cNodes;// total number of nodes - int m_cLinks;// total number of links - int m_nRouteInfo; // size of m_pRouteInfo in bytes. - - // Tables for making nearest node lookup faster. SortedBy provided nodes in a - // order of a particular coordinate. Instead of doing a binary search, RangeStart - // and RangeEnd let you get to the part of SortedBy that you are interested in. - // - // Once you have a point of interest, the only way you'll find a closer point is - // if at least one of the coordinates is closer than the ones you have now. So we - // search each range. After the search is exhausted, we know we have the closest - // node. - // -#define CACHE_SIZE 128 -#define NUM_RANGES 256 - DIST_INFO *m_di; // This is m_cNodes long, but the entries don't correspond to CNode entries. - int m_RangeStart[3][NUM_RANGES]; - int m_RangeEnd[3][NUM_RANGES]; - float m_flShortest; - int m_iNearest; - int m_minX, m_minY, m_minZ, m_maxX, m_maxY, m_maxZ; - int m_minBoxX, m_minBoxY, m_minBoxZ, m_maxBoxX, m_maxBoxY, m_maxBoxZ; - int m_CheckedCounter; - float m_RegionMin[3], m_RegionMax[3]; // The range of nodes. - CACHE_ENTRY m_Cache[CACHE_SIZE]; - - - int m_HashPrimes[16]; - short *m_pHashLinks; - int m_nHashLinks; - - - // kinda sleazy. In order to allow variety in active idles for monster groups in a room with more than one node, - // we keep track of the last node we searched from and store it here. Subsequent searches by other monsters will pick - // up where the last search stopped. - int m_iLastActiveIdleSearch; - - // another such system used to track the search for cover nodes, helps greatly with two monsters trying to get to the same node. - int m_iLastCoverSearch; - - // functions to create the graph - int LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ); - int RejectInlineLinks ( CLink *pLinkPool, FILE *file ); - int FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask); - int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); - int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); - //int FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ); - float PathLength( int iStart, int iDest, int iHull, int afCapMask ); - int NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ); - - enum NODEQUERY { NODEGRAPH_DYNAMIC, NODEGRAPH_STATIC }; - // A static query means we're asking about the possiblity of handling this entity at ANY time - // A dynamic query means we're asking about it RIGHT NOW. So we should query the current state - int HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ); - entvars_t* LinkEntForLink ( CLink *pLink, CNode *pNode ); - void ShowNodeConnections ( int iNode ); - void InitGraph( void ); - int AllocNodes ( void ); - - int CheckNODFile(char *szMapName); - int FLoadGraph(char *szMapName); - int FSaveGraph(char *szMapName); - int FSetGraphPointers(void); - void CheckNode(Vector vecOrigin, int iNode); - - void BuildRegionTables(void); - void ComputeStaticRoutingTables(void); - void TestRoutingTables(void); - - void HashInsert(int iSrcNode, int iDestNode, int iKey); - void HashSearch(int iSrcNode, int iDestNode, int &iKey); - void HashChoosePrimes(int TableSize); - void BuildLinkLookups(void); - - void SortNodes(void); - - int HullIndex( const CBaseEntity *pEntity ); // what hull the monster uses - int NodeType( const CBaseEntity *pEntity ); // what node type the monster uses - inline int CapIndex( int afCapMask ) - { - if (afCapMask & (bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE)) - return 1; - return 0; - } - - - inline CNode &Node( int i ) - { -#ifdef _DEBUG - if ( !m_pNodes || i < 0 || i > m_cNodes ) - ALERT( at_error, "Bad Node!\n" ); -#endif - return m_pNodes[i]; - } - - inline CLink &Link( int i ) - { -#ifdef _DEBUG - if ( !m_pLinkPool || i < 0 || i > m_cLinks ) - ALERT( at_error, "Bad link!\n" ); -#endif - return m_pLinkPool[i]; - } - - inline CLink &NodeLink( int iNode, int iLink ) - { - return Link( Node( iNode ).m_iFirstLink + iLink ); - } - - inline CLink &NodeLink( const CNode &node, int iLink ) - { - return Link( node.m_iFirstLink + iLink ); - } - - inline int INodeLink ( int iNode, int iLink ) - { - return NodeLink( iNode, iLink ).m_iDestNode; - } - -#if 0 - inline CNode &SourceNode( int iNode, int iLink ) - { - return Node( NodeLink( iNode, iLink ).m_iSrcNode ); - } - - inline CNode &DestNode( int iNode, int iLink ) - { - return Node( NodeLink( iNode, iLink ).m_iDestNode ); - } - - inline CNode *PNodeLink ( int iNode, int iLink ) - { - return &DestNode( iNode, iLink ); - } -#endif -}; - -//========================================================= -// Nodes start out as ents in the level. The node graph -// is built, then these ents are discarded. -//========================================================= -class CNodeEnt : public CBaseEntity -{ - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - short m_sHintType; - short m_sHintActivity; -}; - - -//========================================================= -// CStack - last in, first out. -//========================================================= -class CStack -{ -public: - CStack( void ); - void Push( int value ); - int Pop( void ); - int Top( void ); - int Empty( void ) { return m_level==0; } - int Size( void ) { return m_level; } - void CopyToArray ( int *piArray ); - -private: - int m_stack[ MAX_STACK_NODES ]; - int m_level; -}; - - -//========================================================= -// CQueue - first in, first out. -//========================================================= -class CQueue -{ -public: - - CQueue( void );// constructor - inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } - inline int Empty ( void ) { return ( m_cSize == 0 ); } - //inline int Tail ( void ) { return ( m_queue[ m_tail ] ); } - inline int Size ( void ) { return ( m_cSize ); } - void Insert( int, float ); - int Remove( float & ); - -private: - int m_cSize; - struct tag_QUEUE_NODE - { - int Id; - float Priority; - } m_queue[ MAX_STACK_NODES ]; - int m_head; - int m_tail; -}; - -//========================================================= -// CQueuePriority - Priority queue (smallest item out first). -// -//========================================================= -class CQueuePriority -{ -public: - - CQueuePriority( void );// constructor - inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } - inline int Empty ( void ) { return ( m_cSize == 0 ); } - //inline int Tail ( float & ) { return ( m_queue[ m_tail ].Id ); } - inline int Size ( void ) { return ( m_cSize ); } - void Insert( int, float ); - int Remove( float &); - -private: - int m_cSize; - struct tag_HEAP_NODE - { - int Id; - float Priority; - } m_heap[ MAX_STACK_NODES ]; - void Heap_SiftDown(int); - void Heap_SiftUp(void); - -}; - -//========================================================= -// hints - these MUST coincide with the HINTS listed under -// info_node in the FGD file! -//========================================================= -enum -{ - HINT_NONE = 0, - HINT_WORLD_DOOR, - HINT_WORLD_WINDOW, - HINT_WORLD_BUTTON, - HINT_WORLD_MACHINERY, - HINT_WORLD_LEDGE, - HINT_WORLD_LIGHT_SOURCE, - HINT_WORLD_HEAT_SOURCE, - HINT_WORLD_BLINKING_LIGHT, - HINT_WORLD_BRIGHT_COLORS, - HINT_WORLD_HUMAN_BLOOD, - HINT_WORLD_ALIEN_BLOOD, - - HINT_TACTICAL_EXIT = 100, - HINT_TACTICAL_VANTAGE, - HINT_TACTICAL_AMBUSH, - - HINT_STUKA_PERCH = 300, - HINT_STUKA_LANDING, -}; - -extern CGraph WorldGraph; - -#endif // NODES_H diff --git a/sdk/dlls/observer.cpp b/sdk/dlls/observer.cpp deleted file mode 100644 index 0a12c51..0000000 --- a/sdk/dlls/observer.cpp +++ /dev/null @@ -1,280 +0,0 @@ -//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== -// -// The copyright to the contents herein is the property of Valve, L.L.C. -// The contents may be used and/or copied only with the written permission of -// Valve, L.L.C., or in accordance with the terms and conditions stipulated in -// the agreement/contract under which the contents have been supplied. -// -// Purpose: Functionality for the observer chase camera -// -// $Workfile: $ -// $Date: $ -// -//----------------------------------------------------------------------------- -// $Log: $ -// -// $NoKeywords: $ -//============================================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "pm_shared.h" - -extern int gmsgCurWeapon; -extern int gmsgSetFOV; -// Find the next client in the game for this player to spectate -void CBasePlayer::Observer_FindNextPlayer( bool bReverse ) -{ - // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching - // only a subset of the players. e.g. Make it check the target's team. - - int iStart; - if ( m_hObserverTarget ) - iStart = ENTINDEX( m_hObserverTarget->edict() ); - else - iStart = ENTINDEX( edict() ); - int iCurrent = iStart; - m_hObserverTarget = NULL; - int iDir = bReverse ? -1 : 1; - - do - { - iCurrent += iDir; - - // Loop through the clients - if (iCurrent > gpGlobals->maxClients) - iCurrent = 1; - if (iCurrent < 1) - iCurrent = gpGlobals->maxClients; - - CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); - if ( !pEnt ) - continue; - if ( pEnt == this ) - continue; - // Don't spec observers or players who haven't picked a class yet - if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW) ) - continue; - - // MOD AUTHORS: Add checks on target here. - - m_hObserverTarget = pEnt; - break; - - } while ( iCurrent != iStart ); - - // Did we find a target? - if ( m_hObserverTarget ) - { - // Move to the target - UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); - - // ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->netname ) ); - - // Store the target in pev so the physics DLL can get to it - if (pev->iuser1 != OBS_ROAMING) - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - - - - } -} - -// Handle buttons in observer mode -void CBasePlayer::Observer_HandleButtons() -{ - // Slow down mouse clicks - if ( m_flNextObserverInput > gpGlobals->time ) - return; - - // Jump changes from modes: Chase to Roaming - if ( m_afButtonPressed & IN_JUMP ) - { - if ( pev->iuser1 == OBS_CHASE_LOCKED ) - Observer_SetMode( OBS_CHASE_FREE ); - - else if ( pev->iuser1 == OBS_CHASE_FREE ) - Observer_SetMode( OBS_IN_EYE ); - - else if ( pev->iuser1 == OBS_IN_EYE ) - Observer_SetMode( OBS_ROAMING ); - - else if ( pev->iuser1 == OBS_ROAMING ) - Observer_SetMode( OBS_MAP_FREE ); - - else if ( pev->iuser1 == OBS_MAP_FREE ) - Observer_SetMode( OBS_MAP_CHASE ); - - else - Observer_SetMode( OBS_CHASE_FREE ); // don't use OBS_CHASE_LOCKED anymore - - m_flNextObserverInput = gpGlobals->time + 0.2; - } - - // Attack moves to the next player - if ( m_afButtonPressed & IN_ATTACK )//&& pev->iuser1 != OBS_ROAMING ) - { - Observer_FindNextPlayer( false ); - - m_flNextObserverInput = gpGlobals->time + 0.2; - } - - // Attack2 moves to the prev player - if ( m_afButtonPressed & IN_ATTACK2)// && pev->iuser1 != OBS_ROAMING ) - { - Observer_FindNextPlayer( true ); - - m_flNextObserverInput = gpGlobals->time + 0.2; - } -} - -void CBasePlayer::Observer_CheckTarget() -{ - if( pev->iuser1 == OBS_ROAMING ) - return; - - // try to find a traget if we have no current one - if ( m_hObserverTarget == 0) - { - Observer_FindNextPlayer( false ); - - if (m_hObserverTarget == 0) - { - // no target found at all - - int lastMode = pev->iuser1; - - Observer_SetMode( OBS_ROAMING ); - - m_iObserverLastMode = lastMode; // don't overwrite users lastmode - - return; // we still have np target return - } - } - - CBasePlayer* target = (CBasePlayer*)(UTIL_PlayerByIndex( ENTINDEX(m_hObserverTarget->edict()))); - - if ( !target ) - { - Observer_FindNextPlayer( false ); - return; - } - - // check taget - if (target->pev->deadflag == DEAD_DEAD) - { - if ( (target->m_fDeadTime + 2.0f ) < gpGlobals->time ) - { - // 3 secs after death change target - Observer_FindNextPlayer( false ); - return; - } - } -} - -void CBasePlayer::Observer_CheckProperties() -{ - // try to find a traget if we have no current one - if ( pev->iuser1 == OBS_IN_EYE && m_hObserverTarget != 0) - { - CBasePlayer* target = (CBasePlayer*)(UTIL_PlayerByIndex( ENTINDEX(m_hObserverTarget->edict()))); - - if (!target ) - return; - - int weapon = (target->m_pActiveItem!=NULL)?target->m_pActiveItem->m_iId:0; - // use fov of tracked client - if ( m_iFOV != target->m_iFOV || m_iObserverWeapon != weapon ) - { - m_iFOV = target->m_iFOV; - m_iClientFOV = m_iFOV; - // write fov before wepon data, so zoomed crosshair is set correctly - MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); - WRITE_BYTE( m_iFOV ); - MESSAGE_END(); - - - m_iObserverWeapon = weapon; - //send weapon update - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE( 1 ); // 1 = current weapon, not on target - WRITE_BYTE( m_iObserverWeapon ); - WRITE_BYTE( 0 ); // clip - MESSAGE_END(); - } - } - else - { - m_iFOV = 90; - - if ( m_iObserverWeapon != 0 ) - { - m_iObserverWeapon = 0; - - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE( 1 ); // 1 = current weapon - WRITE_BYTE( m_iObserverWeapon ); - WRITE_BYTE( 0 ); // clip - MESSAGE_END(); - } - } -} - -// Attempt to change the observer mode -void CBasePlayer::Observer_SetMode( int iMode ) -{ - - // Just abort if we're changing to the mode we're already in - if ( iMode == pev->iuser1 ) - return; - - // is valid mode ? - if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_MAP_CHASE ) - iMode = OBS_IN_EYE; // now it is - // verify observer target again - if ( m_hObserverTarget != 0) - { - CBaseEntity *pEnt = m_hObserverTarget; - - if ( (pEnt == this) || (pEnt == NULL) ) - m_hObserverTarget = 0; - else if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW) ) - m_hObserverTarget = 0; - } - - // set spectator mode - pev->iuser1 = iMode; - - // if we are not roaming, we need a valid target to track - if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == 0) ) - { - Observer_FindNextPlayer( false ); - - // if we didn't find a valid target switch to roaming - if (m_hObserverTarget == 0) - { - ClientPrint( pev, HUD_PRINTCENTER, "#Spec_NoTarget" ); - pev->iuser1 = OBS_ROAMING; - } - } - - // set target if not roaming - if (pev->iuser1 == OBS_ROAMING) - { - pev->iuser2 = 0; - } - else - pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); - - pev->iuser3 = 0; // clear second target from death cam - - // print spepctaor mode on client screen - - char modemsg[16]; - sprintf(modemsg,"#Spec_Mode%i", pev->iuser1 ); - ClientPrint( pev, HUD_PRINTCENTER, modemsg ); - - m_iObserverLastMode = iMode; -} diff --git a/sdk/dlls/osprey.cpp b/sdk/dlls/osprey.cpp deleted file mode 100644 index 7339b63..0000000 --- a/sdk/dlls/osprey.cpp +++ /dev/null @@ -1,805 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "effects.h" -#include "customentity.h" - -typedef struct -{ - int isValid; - EHANDLE hGrunt; - Vector vecOrigin; - Vector vecAngles; -} t_ospreygrunt; - - - -#define SF_WAITFORTRIGGER 0x40 - - -#define MAX_CARRY 24 - -class COsprey : public CBaseMonster -{ -public: - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void Spawn( void ); - void Precache( void ); - int Classify( void ) { return CLASS_MACHINE; }; - int BloodColor( void ) { return DONT_BLEED; } - void Killed( entvars_t *pevAttacker, int iGib ); - - void UpdateGoal( void ); - BOOL HasDead( void ); - void EXPORT FlyThink( void ); - void EXPORT DeployThink( void ); - void Flight( void ); - void EXPORT HitTouch( CBaseEntity *pOther ); - void EXPORT FindAllThink( void ); - void EXPORT HoverThink( void ); - CBaseMonster *MakeGrunt( Vector vecSrc ); - void EXPORT CrashTouch( CBaseEntity *pOther ); - void EXPORT DyingThink( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - // int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void ShowDamage( void ); - - CBaseEntity *m_pGoalEnt; - Vector m_vel1; - Vector m_vel2; - Vector m_pos1; - Vector m_pos2; - Vector m_ang1; - Vector m_ang2; - float m_startTime; - float m_dTime; - - Vector m_velocity; - - float m_flIdealtilt; - float m_flRotortilt; - - float m_flRightHealth; - float m_flLeftHealth; - - int m_iUnits; - EHANDLE m_hGrunt[MAX_CARRY]; - Vector m_vecOrigin[MAX_CARRY]; - EHANDLE m_hRepel[4]; - - int m_iSoundState; - int m_iSpriteTexture; - - int m_iPitch; - - int m_iExplode; - int m_iTailGibs; - int m_iBodyGibs; - int m_iEngineGibs; - - int m_iDoLeftSmokePuff; - int m_iDoRightSmokePuff; -}; - -LINK_ENTITY_TO_CLASS( monster_osprey, COsprey ); - -TYPEDESCRIPTION COsprey::m_SaveData[] = -{ - DEFINE_FIELD( COsprey, m_pGoalEnt, FIELD_CLASSPTR ), - DEFINE_FIELD( COsprey, m_vel1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_vel2, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_pos1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_pos2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( COsprey, m_ang1, FIELD_VECTOR ), - DEFINE_FIELD( COsprey, m_ang2, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_startTime, FIELD_TIME ), - DEFINE_FIELD( COsprey, m_dTime, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_velocity, FIELD_VECTOR ), - - DEFINE_FIELD( COsprey, m_flIdealtilt, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flRotortilt, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_flRightHealth, FIELD_FLOAT ), - DEFINE_FIELD( COsprey, m_flLeftHealth, FIELD_FLOAT ), - - DEFINE_FIELD( COsprey, m_iUnits, FIELD_INTEGER ), - DEFINE_ARRAY( COsprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY ), - DEFINE_ARRAY( COsprey, m_hRepel, FIELD_EHANDLE, 4 ), - - // DEFINE_FIELD( COsprey, m_iSoundState, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iSpriteTexture, FIELD_INTEGER ), - // DEFINE_FIELD( COsprey, m_iPitch, FIELD_INTEGER ), - - DEFINE_FIELD( COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER ), - DEFINE_FIELD( COsprey, m_iDoRightSmokePuff, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( COsprey, CBaseMonster ); - - -void COsprey :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/osprey.mdl"); - UTIL_SetSize(pev, Vector( -400, -400, -100), Vector(400, 400, 32)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_YES; - m_flRightHealth = 200; - m_flLeftHealth = 200; - pev->health = 400; - - m_flFieldOfView = 0; // 180 degrees - - pev->sequence = 0; - ResetSequenceInfo( ); - pev->frame = RANDOM_LONG(0,0xFF); - - InitBoneControllers(); - - SetThink( &COsprey::FindAllThink ); - SetUse( &COsprey::CommandUse ); - - if (!(pev->spawnflags & SF_WAITFORTRIGGER)) - { - pev->nextthink = gpGlobals->time + 1.0; - } - - m_pos2 = pev->origin; - m_ang2 = pev->angles; - m_vel2 = pev->velocity; -} - - -void COsprey::Precache( void ) -{ - UTIL_PrecacheOther( "monster_human_grunt" ); - - PRECACHE_MODEL("models/osprey.mdl"); - PRECACHE_MODEL("models/HVR.mdl"); - - PRECACHE_SOUND("apache/ap_rotor4.wav"); - PRECACHE_SOUND("weapons/mortarhit.wav"); - - m_iSpriteTexture = PRECACHE_MODEL( "sprites/rope.spr" ); - - m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" ); - m_iTailGibs = PRECACHE_MODEL( "models/osprey_tailgibs.mdl" ); - m_iBodyGibs = PRECACHE_MODEL( "models/osprey_bodygibs.mdl" ); - m_iEngineGibs = PRECACHE_MODEL( "models/osprey_enginegibs.mdl" ); -} - -void COsprey::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - -void COsprey :: FindAllThink( void ) -{ - CBaseEntity *pEntity = NULL; - - m_iUnits = 0; - while (m_iUnits < MAX_CARRY && (pEntity = UTIL_FindEntityByClassname( pEntity, "monster_human_grunt" )) != NULL) - { - if (pEntity->IsAlive()) - { - m_hGrunt[m_iUnits] = pEntity; - m_vecOrigin[m_iUnits] = pEntity->pev->origin; - m_iUnits++; - } - } - - if (m_iUnits == 0) - { - ALERT( at_console, "osprey error: no grunts to resupply\n"); - UTIL_Remove( this ); - return; - } - SetThink( &COsprey::FlyThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_startTime = gpGlobals->time; -} - - -void COsprey :: DeployThink( void ) -{ - UTIL_MakeAimVectors( pev->angles ); - - Vector vecForward = gpGlobals->v_forward; - Vector vecRight = gpGlobals->v_right; - Vector vecUp = gpGlobals->v_up; - - Vector vecSrc; - - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, -4096.0), ignore_monsters, ENT(pev), &tr); - CSoundEnt::InsertSound ( bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3 ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96; - m_hRepel[0] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96; - m_hRepel[1] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96; - m_hRepel[2] = MakeGrunt( vecSrc ); - - vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96; - m_hRepel[3] = MakeGrunt( vecSrc ); - - SetThink( &COsprey::HoverThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -BOOL COsprey :: HasDead( ) -{ - for (int i = 0; i < m_iUnits; i++) - { - if (m_hGrunt[i] == 0 || !m_hGrunt[i]->IsAlive()) - { - return TRUE; - } - else - { - m_vecOrigin[i] = m_hGrunt[i]->pev->origin; // send them to where they died - } - } - return FALSE; -} - - -CBaseMonster *COsprey :: MakeGrunt( Vector vecSrc ) -{ - CBaseEntity *pEntity; - CBaseMonster *pGrunt; - - TraceResult tr; - UTIL_TraceLine( vecSrc, vecSrc + Vector( 0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr); - if ( tr.pHit && Instance( tr.pHit )->pev->solid != SOLID_BSP) - return NULL; - - for (int i = 0; i < m_iUnits; i++) - { - if (m_hGrunt[i] == 0 || !m_hGrunt[i]->IsAlive()) - { - if (m_hGrunt[i] != 0 && m_hGrunt[i]->pev->rendermode == kRenderNormal) - { - m_hGrunt[i]->SUB_StartFadeOut( ); - } - pEntity = Create( "monster_human_grunt", vecSrc, pev->angles ); - pGrunt = pEntity->MyMonsterPointer( ); - pGrunt->pev->movetype = MOVETYPE_FLY; - pGrunt->pev->velocity = Vector( 0, 0, RANDOM_FLOAT( -196, -128 ) ); - pGrunt->SetActivity( ACT_GLIDE ); - - CBeam *pBeam = CBeam::BeamCreate( "sprites/rope.spr", 10 ); - pBeam->PointEntInit( vecSrc + Vector(0,0,112), pGrunt->entindex() ); - pBeam->SetFlags( BEAM_FSOLID ); - pBeam->SetColor( 255, 255, 255 ); - pBeam->SetThink( &CBeam::SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5; - - // ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z ); - pGrunt->m_vecLastPosition = m_vecOrigin[i]; - m_hGrunt[i] = pGrunt; - return pGrunt; - } - } - // ALERT( at_console, "none dead\n"); - return NULL; -} - - -void COsprey :: HoverThink( void ) -{ - int i; - for (i = 0; i < 4; i++) - { - if (m_hRepel[i] != 0 && m_hRepel[i]->pev->health > 0 && !(m_hRepel[i]->pev->flags & FL_ONGROUND)) - { - break; - } - } - - if (i == 4) - { - m_startTime = gpGlobals->time; - SetThink( &COsprey::FlyThink ); - } - - pev->nextthink = gpGlobals->time + 0.1; - UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); -} - - -void COsprey::UpdateGoal( ) -{ - if (m_pGoalEnt) - { - m_pos1 = m_pos2; - m_ang1 = m_ang2; - m_vel1 = m_vel2; - m_pos2 = m_pGoalEnt->pev->origin; - m_ang2 = m_pGoalEnt->pev->angles; - UTIL_MakeAimVectors( Vector( 0, m_ang2.y, 0 ) ); - m_vel2 = gpGlobals->v_forward * m_pGoalEnt->pev->speed; - - m_startTime = m_startTime + m_dTime; - m_dTime = 2.0 * (m_pos1 - m_pos2).Length() / (m_vel1.Length() + m_pGoalEnt->pev->speed); - - if (m_ang1.y - m_ang2.y < -180) - { - m_ang1.y += 360; - } - else if (m_ang1.y - m_ang2.y > 180) - { - m_ang1.y -= 360; - } - - if (m_pGoalEnt->pev->speed < 400) - m_flIdealtilt = 0; - else - m_flIdealtilt = -90; - } - else - { - ALERT( at_console, "osprey missing target"); - } -} - - -void COsprey::FlyThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if ( m_pGoalEnt == NULL && !FStringNull(pev->target) )// this monster has a target - { - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( pev->target ) ) ); - UpdateGoal( ); - } - - if (gpGlobals->time > m_startTime + m_dTime) - { - if (m_pGoalEnt->pev->speed == 0) - { - SetThink( &COsprey::DeployThink ); - } - do { - m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING( m_pGoalEnt->pev->target ) ) ); - } while (m_pGoalEnt->pev->speed < 400 && !HasDead()); - UpdateGoal( ); - } - - Flight( ); - ShowDamage( ); -} - - -void COsprey::Flight( ) -{ - float t = (gpGlobals->time - m_startTime); - float scale = 1.0 / m_dTime; - - float f = UTIL_SplineFraction( t * scale, 1.0 ); - - Vector pos = (m_pos1 + m_vel1 * t) * (1.0 - f) + (m_pos2 - m_vel2 * (m_dTime - t)) * f; - Vector ang = (m_ang1) * (1.0 - f) + (m_ang2) * f; - m_velocity = m_vel1 * (1.0 - f) + m_vel2 * f; - - UTIL_SetOrigin( pev, pos ); - pev->angles = ang; - UTIL_MakeAimVectors( pev->angles ); - float flSpeed = DotProduct( gpGlobals->v_forward, m_velocity ); - - // float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity ); - - float m_flIdealtilt = (160 - flSpeed) / 10.0; - - // ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt ); - if (m_flRotortilt < m_flIdealtilt) - { - m_flRotortilt += 0.5; - if (m_flRotortilt > 0) - m_flRotortilt = 0; - } - if (m_flRotortilt > m_flIdealtilt) - { - m_flRotortilt -= 0.5; - if (m_flRotortilt < -90) - m_flRotortilt = -90; - } - SetBoneController( 0, m_flRotortilt ); - - - if (m_iSoundState == 0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, 0, 110 ); - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 ); - - m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions - } - else - { - CBaseEntity *pPlayer = NULL; - - pPlayer = UTIL_FindEntityByClassname( NULL, "player" ); - // UNDONE: this needs to send different sounds to every player for multiplayer. - if (pPlayer) - { - float pitch = DotProduct( m_velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize() ); - - pitch = (int)(100 + pitch / 75.0); - - if (pitch > 250) - pitch = 250; - if (pitch < 50) - pitch = 50; - - if (pitch == 100) - pitch = 101; - - if (pitch != m_iPitch) - { - m_iPitch = pitch; - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - // ALERT( at_console, "%.0f\n", pitch ); - } - } - // EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch); - } - -} - - -void COsprey::HitTouch( CBaseEntity *pOther ) -{ - pev->nextthink = gpGlobals->time + 2.0; -} - - -/* -int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if (m_flRotortilt <= -90) - { - m_flRotortilt = 0; - } - else - { - m_flRotortilt -= 45; - } - SetBoneController( 0, m_flRotortilt ); - return 0; -} -*/ - - - -void COsprey :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->gravity = 0.3; - pev->velocity = m_velocity; - pev->avelocity = Vector( RANDOM_FLOAT( -20, 20 ), 0, RANDOM_FLOAT( -50, 50 ) ); - STOP_SOUND( ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav" ); - - UTIL_SetSize( pev, Vector( -32, -32, -64), Vector( 32, 32, 0) ); - SetThink( &COsprey::DyingThink ); - SetTouch( &COsprey::CrashTouch ); - pev->nextthink = gpGlobals->time + 0.1; - pev->health = 0; - pev->takedamage = DAMAGE_NO; - - m_startTime = gpGlobals->time + 4.0; -} - -void COsprey::CrashTouch( CBaseEntity *pOther ) -{ - // only crash if we hit something solid - if ( pOther->pev->solid == SOLID_BSP) - { - SetTouch( NULL ); - m_startTime = gpGlobals->time; - pev->nextthink = gpGlobals->time; - m_velocity = pev->velocity; - } -} - - -void COsprey :: DyingThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->avelocity = pev->avelocity * 1.02; - - // still falling? - if (m_startTime > gpGlobals->time ) - { - UTIL_MakeAimVectors( pev->angles ); - ShowDamage( ); - - Vector vecSpot = pev->origin + pev->velocity * 0.2; - - // random explosions - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexFireball ); - WRITE_BYTE( RANDOM_LONG(0,29) + 30 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - WRITE_BYTE( TE_EXPLFLAG_NONE ); - MESSAGE_END(); - - // lots of smoke - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.y + RANDOM_FLOAT( -150, 150 )); - WRITE_COORD( vecSpot.z + RANDOM_FLOAT( -150, -50 )); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 100 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - - - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z ); - - // size - WRITE_COORD( 800 ); - WRITE_COORD( 800 ); - WRITE_COORD( 132 ); - - // velocity - WRITE_COORD( pev->velocity.x ); - WRITE_COORD( pev->velocity.y ); - WRITE_COORD( pev->velocity.z ); - - // randomization - WRITE_BYTE( 50 ); - - // Model - WRITE_SHORT( m_iTailGibs ); //model id# - - // # of shards - WRITE_BYTE( 8 ); // let client decide - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - - - // don't stop it we touch a entity - pev->flags &= ~FL_ONGROUND; - pev->nextthink = gpGlobals->time + 0.2; - return; - } - else - { - Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 10 ); // framerate - MESSAGE_END(); - */ - - // gibs - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_SPRITE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 512 ); - WRITE_SHORT( m_iExplode ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 255 ); // brightness - MESSAGE_END(); - - /* - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 300 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 250 ); // scale * 10 - WRITE_BYTE( 6 ); // framerate - MESSAGE_END(); - */ - - // blast circle - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_BEAMCYLINDER ); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z); - WRITE_COORD( pev->origin.x); - WRITE_COORD( pev->origin.y); - WRITE_COORD( pev->origin.z + 2000 ); // reach damage radius over .2 seconds - WRITE_SHORT( m_iSpriteTexture ); - WRITE_BYTE( 0 ); // startframe - WRITE_BYTE( 0 ); // framerate - WRITE_BYTE( 4 ); // life - WRITE_BYTE( 32 ); // width - WRITE_BYTE( 0 ); // noise - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 192 ); // r, g, b - WRITE_BYTE( 128 ); // brightness - WRITE_BYTE( 0 ); // speed - MESSAGE_END(); - - EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3); - - RadiusDamage( pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST ); - - // gibs - vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5; - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecSpot ); - WRITE_BYTE( TE_BREAKMODEL); - - // position - WRITE_COORD( vecSpot.x ); - WRITE_COORD( vecSpot.y ); - WRITE_COORD( vecSpot.z + 64); - - // size - WRITE_COORD( 800 ); - WRITE_COORD( 800 ); - WRITE_COORD( 128 ); - - // velocity - WRITE_COORD( m_velocity.x ); - WRITE_COORD( m_velocity.y ); - WRITE_COORD( fabs( m_velocity.z ) * 0.25 ); - - // randomization - WRITE_BYTE( 40 ); - - // Model - WRITE_SHORT( m_iBodyGibs ); //model id# - - // # of shards - WRITE_BYTE( 128 ); - - // duration - WRITE_BYTE( 200 );// 10.0 seconds - - // flags - - WRITE_BYTE( BREAK_METAL ); - MESSAGE_END(); - - UTIL_Remove( this ); - } -} - - -void COsprey :: ShowDamage( void ) -{ - if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0,99) > m_flLeftHealth) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * -340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if (m_iDoLeftSmokePuff > 0) - m_iDoLeftSmokePuff--; - } - if (m_iDoRightSmokePuff > 0 || RANDOM_LONG(0,99) > m_flRightHealth) - { - Vector vecSrc = pev->origin + gpGlobals->v_right * 340; - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x ); - WRITE_COORD( vecSrc.y ); - WRITE_COORD( vecSrc.z ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( RANDOM_LONG(0,9) + 20 ); // scale * 10 - WRITE_BYTE( 12 ); // framerate - MESSAGE_END(); - if (m_iDoRightSmokePuff > 0) - m_iDoRightSmokePuff--; - } -} - - -void COsprey::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage ); - - // only so much per engine - if (ptr->iHitgroup == 3) - { - if (m_flRightHealth < 0) - return; - else - m_flRightHealth -= flDamage; - m_iDoLeftSmokePuff = 3 + (flDamage / 5.0); - } - - if (ptr->iHitgroup == 2) - { - if (m_flLeftHealth < 0) - return; - else - m_flLeftHealth -= flDamage; - m_iDoRightSmokePuff = 3 + (flDamage / 5.0); - } - - // hit hard, hits cockpit, hits engines - if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3) - { - // ALERT( at_console, "%.0f\n", flDamage ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } - else - { - UTIL_Sparks( ptr->vecEndPos ); - } -} - - - - - diff --git a/sdk/dlls/pathcorner.cpp b/sdk/dlls/pathcorner.cpp deleted file mode 100644 index b2c1e3f..0000000 --- a/sdk/dlls/pathcorner.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// ========================== PATH_CORNER =========================== -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "trains.h" -#include "saverestore.h" - -class CPathCorner : public CPointEntity -{ -public: - void Spawn( ); - void KeyValue( KeyValueData* pkvd ); - float GetDelay( void ) { return m_flWait; } -// void Touch( CBaseEntity *pOther ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - float m_flWait; -}; - -LINK_ENTITY_TO_CLASS( path_corner, CPathCorner ); - -// Global Savedata for Delay -TYPEDESCRIPTION CPathCorner::m_SaveData[] = -{ - DEFINE_FIELD( CPathCorner, m_flWait, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CPathCorner, CPointEntity ); - -// -// Cache user-entity-field values until spawn is called. -// -void CPathCorner :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - - -void CPathCorner :: Spawn( ) -{ - ASSERTSZ(!FStringNull(pev->targetname), "path_corner without a targetname"); -} - -#if 0 -void CPathCorner :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - if ( FBitSet ( pevToucher->flags, FL_MONSTER ) ) - {// monsters don't navigate path corners based on touch anymore - return; - } - - // If OTHER isn't explicitly looking for this path_corner, bail out - if ( pOther->m_pGoalEnt != this ) - { - return; - } - - // If OTHER has an enemy, this touch is incidental, ignore - if ( !FNullEnt(pevToucher->enemy) ) - { - return; // fighting, not following a path - } - - // UNDONE: support non-zero flWait - /* - if (m_flWait != 0) - ALERT(at_warning, "Non-zero path-cornder waits NYI"); - */ - - // Find the next "stop" on the path, make it the goal of the "toucher". - if (FStringNull(pev->target)) - { - ALERT(at_warning, "PathCornerTouch: no next stop specified"); - } - - pOther->m_pGoalEnt = CBaseEntity::Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(pev->target) ) ); - - // If "next spot" was not found (does not exist - level design error) - if ( !pOther->m_pGoalEnt ) - { - ALERT(at_console, "PathCornerTouch--%s couldn't find next stop in path: %s", STRING(pev->classname), STRING(pev->target)); - return; - } - - // Turn towards the next stop in the path. - pevToucher->ideal_yaw = UTIL_VecToYaw ( pOther->m_pGoalEnt->pev->origin - pevToucher->origin ); -} -#endif - - - -TYPEDESCRIPTION CPathTrack::m_SaveData[] = -{ - DEFINE_FIELD( CPathTrack, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CPathTrack, m_pnext, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_paltpath, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_pprevious, FIELD_CLASSPTR ), - DEFINE_FIELD( CPathTrack, m_altName, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CPathTrack, CBaseEntity ); -LINK_ENTITY_TO_CLASS( path_track, CPathTrack ); - -// -// Cache user-entity-field values until spawn is called. -// -void CPathTrack :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "altpath")) - { - m_altName = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CPathTrack :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int on; - - // Use toggles between two paths - if ( m_paltpath ) - { - on = !FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ); - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - SetBits( pev->spawnflags, SF_PATH_ALTERNATE ); - else - ClearBits( pev->spawnflags, SF_PATH_ALTERNATE ); - } - } - else // Use toggles between enabled/disabled - { - on = !FBitSet( pev->spawnflags, SF_PATH_DISABLED ); - - if ( ShouldToggle( useType, on ) ) - { - if ( on ) - SetBits( pev->spawnflags, SF_PATH_DISABLED ); - else - ClearBits( pev->spawnflags, SF_PATH_DISABLED ); - } - } -} - - -void CPathTrack :: Link( void ) -{ - edict_t *pentTarget; - - if ( !FStringNull(pev->target) ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - if ( !FNullEnt(pentTarget) ) - { - m_pnext = CPathTrack::Instance( pentTarget ); - - if ( m_pnext ) // If no next pointer, this is the end of a path - { - m_pnext->SetPrevious( this ); - } - } - else - ALERT( at_console, "Dead end link %s\n", STRING(pev->target) ); - } - - // Find "alternate" path - if ( m_altName ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_altName) ); - if ( !FNullEnt(pentTarget) ) - { - m_paltpath = CPathTrack::Instance( pentTarget ); - - if ( m_paltpath ) // If no next pointer, this is the end of a path - { - m_paltpath->SetPrevious( this ); - } - } - } -} - - -void CPathTrack :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - - m_pnext = NULL; - m_pprevious = NULL; -// DEBUGGING CODE -#if PATH_SPARKLE_DEBUG - SetThink( Sparkle ); - pev->nextthink = gpGlobals->time + 0.5; -#endif -} - - -void CPathTrack::Activate( void ) -{ - if ( !FStringNull( pev->targetname ) ) // Link to next, and back-link - Link(); -} - -CPathTrack *CPathTrack :: ValidPath( CPathTrack *ppath, int testFlag ) -{ - if ( !ppath ) - return NULL; - - if ( testFlag && FBitSet( ppath->pev->spawnflags, SF_PATH_DISABLED ) ) - return NULL; - - return ppath; -} - - -void CPathTrack :: Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ) -{ - if ( pstart && pend ) - { - Vector dir = (pend->pev->origin - pstart->pev->origin); - dir = dir.Normalize(); - *origin = pend->pev->origin + dir * dist; - } -} - -CPathTrack *CPathTrack::GetNext( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && !FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pnext; -} - - - -CPathTrack *CPathTrack::GetPrevious( void ) -{ - if ( m_paltpath && FBitSet( pev->spawnflags, SF_PATH_ALTERNATE ) && FBitSet( pev->spawnflags, SF_PATH_ALTREVERSE ) ) - return m_paltpath; - - return m_pprevious; -} - - - -void CPathTrack::SetPrevious( CPathTrack *pprev ) -{ - // Only set previous if this isn't my alternate path - if ( pprev && !FStrEq( STRING(pprev->pev->targetname), STRING(m_altName) ) ) - m_pprevious = pprev; -} - - -// Assumes this is ALWAYS enabled -CPathTrack *CPathTrack :: LookAhead( Vector *origin, float dist, int move ) -{ - CPathTrack *pcurrent; - float originalDist = dist; - - pcurrent = this; - Vector currentPos = *origin; - - if ( dist < 0 ) // Travelling backwards through path - { - dist = -dist; - while ( dist > 0 ) - { - Vector dir = pcurrent->pev->origin - currentPos; - float length = dir.Length(); - if ( !length ) - { - if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetNext(), pcurrent, origin, dist ); - return NULL; - } - pcurrent = pcurrent->GetPrevious(); - } - else if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->pev->origin; - *origin = currentPos; - if ( !ValidPath(pcurrent->GetPrevious(), move) ) // If there is no previous node, or it's disabled, return now. - return NULL; - - pcurrent = pcurrent->GetPrevious(); - } - } - *origin = currentPos; - return pcurrent; - } - else - { - while ( dist > 0 ) - { - if ( !ValidPath(pcurrent->GetNext(), move) ) // If there is no next node, or it's disabled, return now. - { - if ( !move ) - Project( pcurrent->GetPrevious(), pcurrent, origin, dist ); - return NULL; - } - Vector dir = pcurrent->GetNext()->pev->origin - currentPos; - float length = dir.Length(); - if ( !length && !ValidPath( pcurrent->GetNext()->GetNext(), move ) ) - { - if ( dist == originalDist ) // HACK -- up against a dead end - return NULL; - return pcurrent; - } - if ( length > dist ) // enough left in this path to move - { - *origin = currentPos + (dir * (dist / length)); - return pcurrent; - } - else - { - dist -= length; - currentPos = pcurrent->GetNext()->pev->origin; - pcurrent = pcurrent->GetNext(); - *origin = currentPos; - } - } - *origin = currentPos; - } - - return pcurrent; -} - - -// Assumes this is ALWAYS enabled -CPathTrack *CPathTrack :: Nearest( Vector origin ) -{ - int deadCount; - float minDist, dist; - Vector delta; - CPathTrack *ppath, *pnearest; - - - delta = origin - pev->origin; - delta.z = 0; - minDist = delta.Length(); - pnearest = this; - ppath = GetNext(); - - // Hey, I could use the old 2 racing pointers solution to this, but I'm lazy :) - deadCount = 0; - while ( ppath && ppath != this ) - { - deadCount++; - if ( deadCount > 9999 ) - { - ALERT( at_error, "Bad sequence of path_tracks from %s", STRING(pev->targetname) ); - return NULL; - } - delta = origin - ppath->pev->origin; - delta.z = 0; - dist = delta.Length(); - if ( dist < minDist ) - { - minDist = dist; - pnearest = ppath; - } - ppath = ppath->GetNext(); - } - return pnearest; -} - - -CPathTrack *CPathTrack::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "path_track" ) ) - return (CPathTrack *)GET_PRIVATE(pent); - return NULL; -} - - - // DEBUGGING CODE -#if PATH_SPARKLE_DEBUG -void CPathTrack :: Sparkle( void ) -{ - - pev->nextthink = gpGlobals->time + 0.2; - if ( FBitSet( pev->spawnflags, SF_PATH_DISABLED ) ) - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 210, 10); - else - UTIL_ParticleEffect(pev->origin, Vector(0,0,100), 84, 10); -} -#endif - diff --git a/sdk/dlls/plane.cpp b/sdk/dlls/plane.cpp deleted file mode 100644 index 39a91c3..0000000 --- a/sdk/dlls/plane.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "plane.h" - -//========================================================= -// Plane -//========================================================= -CPlane :: CPlane ( void ) -{ - m_fInitialized = FALSE; -} - -//========================================================= -// InitializePlane - Takes a normal for the plane and a -// point on the plane and -//========================================================= -void CPlane :: InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ) -{ - m_vecNormal = vecNormal; - m_flDist = DotProduct ( m_vecNormal, vecPoint ); - m_fInitialized = TRUE; -} - - -//========================================================= -// PointInFront - determines whether the given vector is -// in front of the plane. -//========================================================= -BOOL CPlane :: PointInFront ( const Vector &vecPoint ) -{ - float flFace; - - if ( !m_fInitialized ) - { - return FALSE; - } - - flFace = DotProduct ( m_vecNormal, vecPoint ) - m_flDist; - - if ( flFace >= 0 ) - { - return TRUE; - } - - return FALSE; -} - diff --git a/sdk/dlls/plane.h b/sdk/dlls/plane.h deleted file mode 100644 index af70f1c..0000000 --- a/sdk/dlls/plane.h +++ /dev/null @@ -1,43 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLANE_H -#define PLANE_H - -//========================================================= -// Plane -//========================================================= -class CPlane -{ -public: - CPlane ( void ); - - //========================================================= - // InitializePlane - Takes a normal for the plane and a - // point on the plane and - //========================================================= - void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ); - - //========================================================= - // PointInFront - determines whether the given vector is - // in front of the plane. - //========================================================= - BOOL PointInFront ( const Vector &vecPoint ); - - Vector m_vecNormal; - float m_flDist; - BOOL m_fInitialized; -}; - -#endif // PLANE_H diff --git a/sdk/dlls/plats.cpp b/sdk/dlls/plats.cpp deleted file mode 100644 index 3b10951..0000000 --- a/sdk/dlls/plats.cpp +++ /dev/null @@ -1,2285 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== plats.cpp ======================================================== - - spawn, think, and touch functions for trains, etc - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "trains.h" -#include "saverestore.h" - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform); - -#define SF_PLAT_TOGGLE 0x0001 - -class CBasePlatTrain : public CBaseToggle -{ -public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void KeyValue( KeyValueData* pkvd); - void Precache( void ); - - // This is done to fix spawn flag collisions between this class and a derived class - virtual BOOL IsTogglePlat( void ) { return (pev->spawnflags & SF_PLAT_TOGGLE) ? TRUE : FALSE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - BYTE m_bMoveSnd; // sound a plat makes while moving - BYTE m_bStopSnd; // sound a plat makes when it stops - float m_volume; // Sound volume -}; - -TYPEDESCRIPTION CBasePlatTrain::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlatTrain, m_bMoveSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_bStopSnd, FIELD_CHARACTER ), - DEFINE_FIELD( CBasePlatTrain, m_volume, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CBasePlatTrain, CBaseToggle ); - -void CBasePlatTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_flHeight = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "rotation")) - { - m_vecFinalAngle.x = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "movesnd")) - { - m_bMoveSnd = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "stopsnd")) - { - m_bStopSnd = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_volume = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -#define noiseMoving noise -#define noiseArrived noise1 - -void CBasePlatTrain::Precache( void ) -{ -// set the plat's "in-motion" sound - switch (m_bMoveSnd) - { - case 0: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/bigmove2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/elevmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/elevmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/elevmove3.wav"); - pev->noiseMoving = MAKE_STRING("plats/elevmove3.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/freightmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/freightmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/freightmove2.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/heavymove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/heavymove1.wav"); - break; - case 9: - PRECACHE_SOUND ("plats/rackmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/rackmove1.wav"); - break; - case 10: - PRECACHE_SOUND ("plats/railmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/railmove1.wav"); - break; - case 11: - PRECACHE_SOUND ("plats/squeekmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/squeekmove1.wav"); - break; - case 12: - PRECACHE_SOUND ("plats/talkmove1.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove1.wav"); - break; - case 13: - PRECACHE_SOUND ("plats/talkmove2.wav"); - pev->noiseMoving = MAKE_STRING("plats/talkmove2.wav"); - break; - default: - pev->noiseMoving = MAKE_STRING("common/null.wav"); - break; - } - -// set the plat's 'reached destination' stop sound - switch (m_bStopSnd) - { - case 0: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - case 1: - PRECACHE_SOUND ("plats/bigstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop1.wav"); - break; - case 2: - PRECACHE_SOUND ("plats/bigstop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/bigstop2.wav"); - break; - case 3: - PRECACHE_SOUND ("plats/freightstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/freightstop1.wav"); - break; - case 4: - PRECACHE_SOUND ("plats/heavystop2.wav"); - pev->noiseArrived = MAKE_STRING("plats/heavystop2.wav"); - break; - case 5: - PRECACHE_SOUND ("plats/rackstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/rackstop1.wav"); - break; - case 6: - PRECACHE_SOUND ("plats/railstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/railstop1.wav"); - break; - case 7: - PRECACHE_SOUND ("plats/squeekstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/squeekstop1.wav"); - break; - case 8: - PRECACHE_SOUND ("plats/talkstop1.wav"); - pev->noiseArrived = MAKE_STRING("plats/talkstop1.wav"); - break; - - default: - pev->noiseArrived = MAKE_STRING("common/null.wav"); - break; - } -} - -// -//====================== PLAT code ==================================================== -// - - -#define noiseMovement noise -#define noiseStopMoving noise1 - -class CFuncPlat : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Setup( void ); - - virtual void Blocked( CBaseEntity *pOther ); - - - void EXPORT PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - void EXPORT CallGoDown( void ) { GoDown(); } - void EXPORT CallHitTop( void ) { HitTop(); } - void EXPORT CallHitBottom( void ) { HitBottom(); } - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); -}; -LINK_ENTITY_TO_CLASS( func_plat, CFuncPlat ); - - -// UNDONE: Need to save this!!! It needs class & linkage -class CPlatTrigger : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } - void SpawnInsideTrigger( CFuncPlat *pPlatform ); - void Touch( CBaseEntity *pOther ); - CFuncPlat *m_pPlatform; -}; - - - -/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER -speed default 150 - -Plats are always drawn in the extended position, so they will light correctly. - -If the plat is the target of another trigger or button, it will start out disabled in -the extended position until it is trigger, when it will lower and become a normal plat. - -If the "height" key is set, that will determine the amount the plat moves, instead of -being implicitly determined by the model's height. - -Set "sounds" to one of the following: -1) base fast -2) chain slow -*/ - -void CFuncPlat :: Setup( void ) -{ - //pev->noiseMovement = MAKE_STRING("plats/platmove1.wav"); - //pev->noiseStopMoving = MAKE_STRING("plats/platstop1.wav"); - - if (m_flTLength == 0) - m_flTLength = 80; - if (m_flTWidth == 0) - m_flTWidth = 10; - - pev->angles = g_vecZero; - - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); // set size and link into world - UTIL_SetSize(pev, pev->mins, pev->maxs); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - // vecPosition1 is the top position, vecPosition2 is the bottom - m_vecPosition1 = pev->origin; - m_vecPosition2 = pev->origin; - if (m_flHeight != 0) - m_vecPosition2.z = pev->origin.z - m_flHeight; - else - m_vecPosition2.z = pev->origin.z - pev->size.z + 8; - if (pev->speed == 0) - pev->speed = 150; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncPlat :: Precache( ) -{ - CBasePlatTrain::Precache(); - //PRECACHE_SOUND("plats/platmove1.wav"); - //PRECACHE_SOUND("plats/platstop1.wav"); - if ( !IsTogglePlat() ) - PlatSpawnInsideTrigger( pev ); // the "start moving" trigger -} - - -void CFuncPlat :: Spawn( ) -{ - Setup(); - - Precache(); - - // If this platform is the target of some button, it starts at the TOP position, - // and is brought down by that button. Otherwise, it starts at BOTTOM. - if ( !FStringNull(pev->targetname) ) - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - SetUse( &CFuncPlat::PlatUse ); - } - else - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - } -} - - - -static void PlatSpawnInsideTrigger(entvars_t* pevPlatform) -{ - GetClassPtr( (CPlatTrigger *)NULL)->SpawnInsideTrigger( GetClassPtr( (CFuncPlat *)pevPlatform ) ); -} - - -// -// Create a trigger entity for a platform. -// -void CPlatTrigger :: SpawnInsideTrigger( CFuncPlat *pPlatform ) -{ - m_pPlatform = pPlatform; - // Create trigger entity, "point" it at the owning platform, give it a touch method - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - pev->origin = pPlatform->pev->origin; - - // Establish the trigger field's size - Vector vecTMin = m_pPlatform->pev->mins + Vector ( 25 , 25 , 0 ); - Vector vecTMax = m_pPlatform->pev->maxs + Vector ( 25 , 25 , 8 ); - vecTMin.z = vecTMax.z - ( m_pPlatform->m_vecPosition1.z - m_pPlatform->m_vecPosition2.z + 8 ); - if (m_pPlatform->pev->size.x <= 50) - { - vecTMin.x = (m_pPlatform->pev->mins.x + m_pPlatform->pev->maxs.x) / 2; - vecTMax.x = vecTMin.x + 1; - } - if (m_pPlatform->pev->size.y <= 50) - { - vecTMin.y = (m_pPlatform->pev->mins.y + m_pPlatform->pev->maxs.y) / 2; - vecTMax.y = vecTMin.y + 1; - } - UTIL_SetSize ( pev, vecTMin, vecTMax ); -} - - -// -// When the platform's trigger field is touched, the platform ??? -// -void CPlatTrigger :: Touch( CBaseEntity *pOther ) -{ - // Ignore touches by non-players - entvars_t* pevToucher = pOther->pev; - if ( !FClassnameIs (pevToucher, "player") ) - return; - - // Ignore touches by corpses - if (!pOther->IsAlive()||!m_pPlatform||!m_pPlatform->pev) - return; - - // Make linked platform go up/down. - if (m_pPlatform->m_toggle_state == TS_AT_BOTTOM) - m_pPlatform->GoUp(); - else if (m_pPlatform->m_toggle_state == TS_AT_TOP) - m_pPlatform->pev->nextthink = m_pPlatform->pev->ltime + 1;// delay going down -} - - -// -// Used by SUB_UseTargets, when a platform is the target of a button. -// Start bringing platform down. -// -void CFuncPlat :: PlatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( IsTogglePlat() ) - { - // Top is off, bottom is on - BOOL on = (m_toggle_state == TS_AT_BOTTOM) ? TRUE : FALSE; - - if ( !ShouldToggle( useType, on ) ) - return; - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else if ( m_toggle_state == TS_AT_BOTTOM ) - GoUp(); - } - else - { - SetUse( NULL ); - - if (m_toggle_state == TS_AT_TOP) - GoDown(); - } -} - - -// -// Platform is at top, now starts moving down. -// -void CFuncPlat :: GoDown( void ) -{ - if(pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_TOP || m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_GOING_DOWN; - SetMoveDone(&CFuncPlat::CallHitBottom); - LinearMove(m_vecPosition2, pev->speed); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlat :: HitBottom( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_AT_BOTTOM; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlat :: GoUp( void ) -{ - if (pev->noiseMovement) - EMIT_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_AT_BOTTOM || m_toggle_state == TS_GOING_DOWN); - m_toggle_state = TS_GOING_UP; - SetMoveDone(&CFuncPlat::CallHitTop); - LinearMove(m_vecPosition1, pev->speed); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlat :: HitTop( void ) -{ - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - if (pev->noiseStopMoving) - EMIT_SOUND(ENT(pev), CHAN_WEAPON, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - - ASSERT(m_toggle_state == TS_GOING_UP); - m_toggle_state = TS_AT_TOP; - - if ( !IsTogglePlat() ) - { - // After a delay, the platform will automatically start going down again. - SetThink( &CFuncPlat::CallGoDown ); - pev->nextthink = pev->ltime + 3; - } -} - - -void CFuncPlat :: Blocked( CBaseEntity *pOther ) -{ - ALERT( at_aiconsole, "%s Blocked by %s\n", STRING(pev->classname), STRING(pOther->pev->classname) ); - // Hurt the blocker a little - pOther->TakeDamage(pev, pev, 1, DMG_CRUSH); - - if(pev->noiseMovement) - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement)); - - // Send the platform back where it came from - ASSERT(m_toggle_state == TS_GOING_UP || m_toggle_state == TS_GOING_DOWN); - if (m_toggle_state == TS_GOING_UP) - GoDown(); - else if (m_toggle_state == TS_GOING_DOWN) - GoUp (); -} - - -class CFuncPlatRot : public CFuncPlat -{ -public: - void Spawn( void ); - void SetupRotation( void ); - - virtual void GoUp( void ); - virtual void GoDown( void ); - virtual void HitTop( void ); - virtual void HitBottom( void ); - - void RotMove( Vector &destAngle, float time ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - Vector m_end, m_start; -}; -LINK_ENTITY_TO_CLASS( func_platrot, CFuncPlatRot ); -TYPEDESCRIPTION CFuncPlatRot::m_SaveData[] = -{ - DEFINE_FIELD( CFuncPlatRot, m_end, FIELD_VECTOR ), - DEFINE_FIELD( CFuncPlatRot, m_start, FIELD_VECTOR ), -}; - -IMPLEMENT_SAVERESTORE( CFuncPlatRot, CFuncPlat ); - - -void CFuncPlatRot :: SetupRotation( void ) -{ - if ( m_vecFinalAngle.x != 0 ) // This plat rotates too! - { - CBaseToggle :: AxisDir( pev ); - m_start = pev->angles; - m_end = pev->angles + pev->movedir * m_vecFinalAngle.x; - } - else - { - m_start = g_vecZero; - m_end = g_vecZero; - } - if ( !FStringNull(pev->targetname) ) // Start at top - { - pev->angles = m_end; - } -} - - -void CFuncPlatRot :: Spawn( void ) -{ - CFuncPlat :: Spawn(); - SetupRotation(); -} - -void CFuncPlatRot :: GoDown( void ) -{ - CFuncPlat :: GoDown(); - RotMove( m_start, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncPlatRot :: HitBottom( void ) -{ - CFuncPlat :: HitBottom(); - pev->avelocity = g_vecZero; - pev->angles = m_start; -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncPlatRot :: GoUp( void ) -{ - CFuncPlat :: GoUp(); - RotMove( m_end, pev->nextthink - pev->ltime ); -} - - -// -// Platform has hit top. Pauses, then starts back down again. -// -void CFuncPlatRot :: HitTop( void ) -{ - CFuncPlat :: HitTop(); - pev->avelocity = g_vecZero; - pev->angles = m_end; -} - - -void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) -{ - // set destdelta to the vector needed to move - Vector vecDestDelta = destAngle - pev->angles; - - // Travel time is so short, we're practically there already; so make it so. - if ( time >= 0.1) - pev->avelocity = vecDestDelta / time; - else - { - pev->avelocity = vecDestDelta; - pev->nextthink = pev->ltime + 1; - } -} - - -// -//====================== TRAIN code ================================================== -// - -class CFuncTrain : public CBasePlatTrain -{ -public: - void Spawn( void ); - void Precache( void ); - void Activate( void ); - void OverrideReset( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData *pkvd ); - - - void EXPORT Wait( void ); - void EXPORT Next( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - entvars_t *m_pevCurrentTarget; - int m_sounds; - BOOL m_activated; -}; - -LINK_ENTITY_TO_CLASS( func_train, CFuncTrain ); -TYPEDESCRIPTION CFuncTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrain, m_pevCurrentTarget, FIELD_EVARS ), - DEFINE_FIELD( CFuncTrain, m_activated, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrain, CBasePlatTrain ); - - -void CFuncTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBasePlatTrain::KeyValue( pkvd ); -} - - -void CFuncTrain :: Blocked( CBaseEntity *pOther ) - -{ - if ( gpGlobals->time < m_flActivateFinished) - return; - - m_flActivateFinished = gpGlobals->time + 0.5; - - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) - { - // Move toward my target - pev->spawnflags &= ~SF_TRAIN_WAIT_RETRIGGER; - Next(); - } - else - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // Pop back to last target if it's available - if ( pev->enemy ) - pev->target = pev->enemy->v.targetname; - pev->nextthink = 0; - pev->velocity = g_vecZero; - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - } -} - - -void CFuncTrain :: Wait( void ) -{ - // Fire the pass target if there is one - if ( m_pevCurrentTarget->message ) - { - FireTargets( STRING(m_pevCurrentTarget->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pevCurrentTarget->spawnflags, SF_CORNER_FIREONCE ) ) - m_pevCurrentTarget->message = 0; - } - - // need pointer to LAST target. - if ( FBitSet (m_pevCurrentTarget->spawnflags , SF_TRAIN_WAIT_RETRIGGER ) || ( pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER ) ) - { - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - // clear the sound channel. - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - pev->nextthink = 0; - return; - } - - // ALERT ( at_console, "%f\n", m_flWait ); - - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - SetThink( &CFuncTrain::Next ); - } - else - { - Next();// do it RIGHT now! - } -} - - -// -// Train next - path corner needs to change to next target -// -void CFuncTrain :: Next( void ) -{ - CBaseEntity *pTarg; - - - // now find our next target - pTarg = GetNextTarget(); - - if ( !pTarg ) - { - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - // Play stop sound - if ( pev->noiseStopMoving ) - EMIT_SOUND (ENT(pev), CHAN_VOICE, (char*)STRING(pev->noiseStopMoving), m_volume, ATTN_NORM); - return; - } - - // Save last target in case we need to find it again - pev->message = pev->target; - - pev->target = pTarg->pev->target; - m_flWait = pTarg->GetDelay(); - - if ( m_pevCurrentTarget && m_pevCurrentTarget->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = m_pevCurrentTarget->speed; - ALERT( at_aiconsole, "Train %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - m_pevCurrentTarget = pTarg->pev;// keep track of this since path corners change our target for us. - - pev->enemy = pTarg->edict();//hack - - if(FBitSet(m_pevCurrentTarget->spawnflags, SF_CORNER_TELEPORT)) - { - // Path corner has indicated a teleport to the next corner. - SetBits(pev->effects, EF_NOINTERP); - UTIL_SetOrigin(pev, pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5); - Wait(); // Get on with doing the next path corner. - } - else - { - // Normal linear move. - - // CHANGED this from CHAN_VOICE to CHAN_STATIC around OEM beta time because trains should - // use CHAN_STATIC for their movement sounds to prevent sound field problems. - // this is not a hack or temporary fix, this is how things should be. (sjb). - if ( pev->noiseMovement ) - STOP_SOUND( edict(), CHAN_STATIC, (char*)STRING(pev->noiseMovement) ); - if ( pev->noiseMovement ) - EMIT_SOUND (ENT(pev), CHAN_STATIC, (char*)STRING(pev->noiseMovement), m_volume, ATTN_NORM); - ClearBits(pev->effects, EF_NOINTERP); - SetMoveDone( &CFuncTrain::Wait ); - LinearMove (pTarg->pev->origin - (pev->mins + pev->maxs)* 0.5, pev->speed); - } -} - - -void CFuncTrain :: Activate( void ) -{ - // Not yet active, so teleport to first target - if ( !m_activated ) - { - m_activated = TRUE; - entvars_t *pevTarg = VARS( FIND_ENTITY_BY_TARGETNAME (NULL, STRING(pev->target) ) ); - - pev->target = pevTarg->target; - m_pevCurrentTarget = pevTarg;// keep track of this since path corners change our target for us. - - UTIL_SetOrigin (pev, pevTarg->origin - (pev->mins + pev->maxs) * 0.5 ); - - if ( FStringNull(pev->targetname) ) - { // not triggered, so start immediately - pev->nextthink = pev->ltime + 0.1; - SetThink( &CFuncTrain::Next ); - } - else - pev->spawnflags |= SF_TRAIN_WAIT_RETRIGGER; - } -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrain :: Spawn( void ) -{ - Precache(); - if (pev->speed == 0) - pev->speed = 100; - - if ( FStringNull(pev->target) ) - ALERT(at_console, "FuncTrain with no target"); - - if (pev->dmg == 0) - pev->dmg = 2; - - pev->movetype = MOVETYPE_PUSH; - - if ( FBitSet (pev->spawnflags, SF_TRACKTRAIN_PASSABLE) ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - UTIL_SetSize (pev, pev->mins, pev->maxs); - UTIL_SetOrigin(pev, pev->origin); - - m_activated = FALSE; - - if ( m_volume == 0 ) - m_volume = 0.85; -} - - -void CFuncTrain::Precache( void ) -{ - CBasePlatTrain::Precache(); - -#if 0 // obsolete - // otherwise use preset sound - switch (m_sounds) - { - case 0: - pev->noise = 0; - pev->noise1 = 0; - break; - - case 1: - PRECACHE_SOUND ("plats/train2.wav"); - PRECACHE_SOUND ("plats/train1.wav"); - pev->noise = MAKE_STRING("plats/train2.wav"); - pev->noise1 = MAKE_STRING("plats/train1.wav"); - break; - - case 2: - PRECACHE_SOUND ("plats/platmove1.wav"); - PRECACHE_SOUND ("plats/platstop1.wav"); - pev->noise = MAKE_STRING("plats/platstop1.wav"); - pev->noise1 = MAKE_STRING("plats/platmove1.wav"); - break; - } -#endif -} - - -void CFuncTrain::OverrideReset( void ) -{ - CBaseEntity *pTarg; - - // Are we moving? - if ( pev->velocity != g_vecZero && pev->nextthink != 0 ) - { - pev->target = pev->message; - // now find our next target - pTarg = GetNextTarget(); - if ( !pTarg ) - { - pev->nextthink = 0; - pev->velocity = g_vecZero; - } - else // Keep moving for 0.1 secs, then find path_corner again and restart - { - SetThink( &CFuncTrain::Next ); - pev->nextthink = pev->ltime + 0.1; - } - } -} - - - - -// --------------------------------------------------------------------- -// -// Track Train -// -// --------------------------------------------------------------------- - -TYPEDESCRIPTION CFuncTrackTrain::m_SaveData[] = -{ - DEFINE_FIELD( CFuncTrackTrain, m_ppath, FIELD_CLASSPTR ), - DEFINE_FIELD( CFuncTrackTrain, m_length, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_height, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_speed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_dir, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_startSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMins, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_controlMaxs, FIELD_VECTOR ), - DEFINE_FIELD( CFuncTrackTrain, m_sounds, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackTrain, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_flBank, FIELD_FLOAT ), - DEFINE_FIELD( CFuncTrackTrain, m_oldSpeed, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackTrain, CBaseEntity ); -LINK_ENTITY_TO_CLASS( func_tracktrain, CFuncTrackTrain ); - -void CFuncTrackTrain :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wheels")) - { - m_length = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "height")) - { - m_height = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "startspeed")) - { - m_startSpeed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sounds")) - { - m_sounds = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = (float) (atoi(pkvd->szValue)); - m_flVolume *= 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "bank")) - { - m_flBank = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -void CFuncTrackTrain :: NextThink( float thinkTime, BOOL alwaysThink ) -{ - if ( alwaysThink ) - pev->flags |= FL_ALWAYSTHINK; - else - pev->flags &= ~FL_ALWAYSTHINK; - - pev->nextthink = thinkTime; -} - - -void CFuncTrackTrain :: Blocked( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - // Blocker is on-ground on the train - if ( FBitSet( pevOther->flags, FL_ONGROUND ) && VARS(pevOther->groundentity) == pev ) - { - float deltaSpeed = fabs(pev->speed); - if ( deltaSpeed > 50 ) - deltaSpeed = 50; - if ( !pevOther->velocity.z ) - pevOther->velocity.z += deltaSpeed; - return; - } - else - pevOther->velocity = (pevOther->origin - pev->origin ).Normalize() * pev->dmg; - - ALERT( at_aiconsole, "TRAIN(%s): Blocked by %s (dmg:%.2f)\n", STRING(pev->targetname), STRING(pOther->pev->classname), pev->dmg ); - if ( pev->dmg <= 0 ) - return; - // we can't hurt this thing, so we're not concerned with it - pOther->TakeDamage(pev, pev, pev->dmg, DMG_CRUSH); -} - - -void CFuncTrackTrain :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( useType != USE_SET ) - { - if ( !ShouldToggle( useType, (pev->speed != 0) ) ) - return; - - if ( pev->speed == 0 ) - { - pev->speed = m_speed * m_dir; - - Next(); - } - else - { - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - StopSound(); - SetThink( NULL ); - } - } - else - { - float delta = value; - - delta = ((int)(pev->speed * 4) / (int)m_speed)*0.25 + 0.25 * delta; - if ( delta > 1 ) - delta = 1; - else if ( delta < -1 ) - delta = -1; - if ( pev->spawnflags & SF_TRACKTRAIN_FORWARDONLY ) - { - if ( delta < 0 ) - delta = 0; - } - pev->speed = m_speed * delta; - Next(); - ALERT( at_aiconsole, "TRAIN(%s), speed to %.2f\n", STRING(pev->targetname), pev->speed ); - } -} - - -static float Fix( float angle ) -{ - while ( angle < 0 ) - angle += 360; - while ( angle > 360 ) - angle -= 360; - - return angle; -} - - -static void FixupAngles( Vector &v ) -{ - v.x = Fix( v.x ); - v.y = Fix( v.y ); - v.z = Fix( v.z ); -} - -#define TRAIN_STARTPITCH 60 -#define TRAIN_MAXPITCH 200 -#define TRAIN_MAXSPEED 1000 // approx max speed for sound pitch calculation - -void CFuncTrackTrain :: StopSound( void ) -{ - // if sound playing, stop it - if (m_soundPlaying && pev->noise) - { - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - - us_encode = us_sound; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 ); - - /* - STOP_SOUND(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise)); - */ - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100); - } - - m_soundPlaying = 0; -} - -// update pitch based on speed, start sound if not playing -// NOTE: when train goes through transition, m_soundPlaying should go to 0, -// which will cause the looped sound to restart. - -void CFuncTrackTrain :: UpdateSound( void ) -{ - float flpitch; - - if (!pev->noise) - return; - - flpitch = TRAIN_STARTPITCH + (abs(static_cast(pev->speed)) * (TRAIN_MAXPITCH - TRAIN_STARTPITCH) / TRAIN_MAXSPEED); - - if (!m_soundPlaying) - { - // play startup sound for train - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100); - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, 0, (int) flpitch); - m_soundPlaying = 1; - } - else - { -/* - // update pitch - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, (char*)STRING(pev->noise), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int) flpitch); -*/ - // volume 0.0 - 1.0 - 6 bits - // m_sounds 3 bits - // flpitch = 6 bits - // 15 bits total - - unsigned short us_encode; - unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12; - unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6; - unsigned short us_volume = ( ( unsigned short )( m_flVolume * 40.0 ) & 0x003f ); - - us_encode = us_sound | us_pitch | us_volume; - - PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0, - (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 ); - } -} - - -void CFuncTrackTrain :: Next( void ) -{ - float time = 0.5; - - if ( !pev->speed ) - { - ALERT( at_aiconsole, "TRAIN(%s): Speed is 0\n", STRING(pev->targetname) ); - StopSound(); - return; - } - -// if ( !m_ppath ) -// m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - { - ALERT( at_aiconsole, "TRAIN(%s): Lost path\n", STRING(pev->targetname) ); - StopSound(); - return; - } - - UpdateSound(); - - Vector nextPos = pev->origin; - - nextPos.z -= m_height; - CPathTrack *pnext = m_ppath->LookAhead( &nextPos, pev->speed * 0.1, 1 ); - nextPos.z += m_height; - - pev->velocity = (nextPos - pev->origin) * 10; - Vector nextFront = pev->origin; - - nextFront.z -= m_height; - if ( m_length > 0 ) - m_ppath->LookAhead( &nextFront, m_length, 0 ); - else - m_ppath->LookAhead( &nextFront, 100, 0 ); - nextFront.z += m_height; - - Vector delta = nextFront - pev->origin; - Vector angles = UTIL_VecToAngles( delta ); - // The train actually points west - angles.y += 180; - - // !!! All of this crap has to be done to make the angles not wrap around, revisit this. - FixupAngles( angles ); - FixupAngles( pev->angles ); - - if ( !pnext || (delta.x == 0 && delta.y == 0) ) - angles = pev->angles; - - float vy, vx; - if ( !(pev->spawnflags & SF_TRACKTRAIN_NOPITCH) ) - vx = UTIL_AngleDistance( angles.x, pev->angles.x ); - else - vx = 0; - vy = UTIL_AngleDistance( angles.y, pev->angles.y ); - - pev->avelocity.y = vy * 10; - pev->avelocity.x = vx * 10; - - if ( m_flBank != 0 ) - { - if ( pev->avelocity.y < -5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( -m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else if ( pev->avelocity.y > 5 ) - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( m_flBank, pev->angles.z, m_flBank*2 ), pev->angles.z); - else - pev->avelocity.z = UTIL_AngleDistance( UTIL_ApproachAngle( 0, pev->angles.z, m_flBank*4 ), pev->angles.z) * 4; - } - - if ( pnext ) - { - if ( pnext != m_ppath ) - { - CPathTrack *pFire; - if ( pev->speed >= 0 ) - pFire = pnext; - else - pFire = m_ppath; - - m_ppath = pnext; - // Fire the pass target if there is one - if ( pFire->pev->message ) - { - FireTargets( STRING(pFire->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pFire->pev->spawnflags, SF_PATH_FIREONCE ) ) - pFire->pev->message = 0; - } - - if ( pFire->pev->spawnflags & SF_PATH_DISABLE_TRAIN ) - pev->spawnflags |= SF_TRACKTRAIN_NOCONTROL; - - // Don't override speed if under user control - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - { - if ( pFire->pev->speed != 0 ) - {// don't copy speed from target if it is 0 (uninitialized) - pev->speed = pFire->pev->speed; - ALERT( at_aiconsole, "TrackTrain %s speed to %4.2f\n", STRING(pev->targetname), pev->speed ); - } - } - - } - SetThink( &CFuncTrackTrain::Next ); - NextThink( pev->ltime + time, TRUE ); - } - else // end of path, stop - { - StopSound(); - pev->velocity = (nextPos - pev->origin); - pev->avelocity = g_vecZero; - float distance = pev->velocity.Length(); - m_oldSpeed = pev->speed; - - - pev->speed = 0; - - // Move to the dead end - - // Are we there yet? - if ( distance > 0 ) - { - // no, how long to get there? - time = distance / m_oldSpeed; - pev->velocity = pev->velocity * (m_oldSpeed / distance); - SetThink( &CFuncTrackTrain::DeadEnd ); - NextThink( pev->ltime + time, FALSE ); - } - else - { - DeadEnd(); - } - } -} - - -void CFuncTrackTrain::DeadEnd( void ) -{ - // Fire the dead-end target if there is one - CPathTrack *pTrack, *pNext; - - pTrack = m_ppath; - - ALERT( at_aiconsole, "TRAIN(%s): Dead end ", STRING(pev->targetname) ); - // Find the dead end path node - // HACKHACK -- This is bugly, but the train can actually stop moving at a different node depending on it's speed - // so we have to traverse the list to it's end. - if ( pTrack ) - { - if ( m_oldSpeed < 0 ) - { - do - { - pNext = pTrack->ValidPath( pTrack->GetPrevious(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - else - { - do - { - pNext = pTrack->ValidPath( pTrack->GetNext(), TRUE ); - if ( pNext ) - pTrack = pNext; - } while ( pNext ); - } - } - - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - if ( pTrack ) - { - ALERT( at_aiconsole, "at %s\n", STRING(pTrack->pev->targetname) ); - if ( pTrack->pev->netname ) - FireTargets( STRING(pTrack->pev->netname), this, this, USE_TOGGLE, 0 ); - } - else - ALERT( at_aiconsole, "\n" ); -} - - -void CFuncTrackTrain :: SetControls( entvars_t *pevControls ) -{ - Vector offset = pevControls->origin - pev->oldorigin; - - m_controlMins = pevControls->mins + offset; - m_controlMaxs = pevControls->maxs + offset; -} - - -BOOL CFuncTrackTrain :: OnControls( entvars_t *pevTest ) -{ - Vector offset = pevTest->origin - pev->origin; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOCONTROL ) - return FALSE; - - // Transform offset into local coordinates - UTIL_MakeVectors( pev->angles ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = -DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - if ( local.x >= m_controlMins.x && local.y >= m_controlMins.y && local.z >= m_controlMins.z && - local.x <= m_controlMaxs.x && local.y <= m_controlMaxs.y && local.z <= m_controlMaxs.z ) - return TRUE; - - return FALSE; -} - - -void CFuncTrackTrain :: Find( void ) -{ - m_ppath = CPathTrack::Instance(FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) )); - if ( !m_ppath ) - return; - - entvars_t *pevTarget = m_ppath->pev; - if ( !FClassnameIs( pevTarget, "path_track" ) ) - { - ALERT( at_error, "func_track_train must be on a path of path_track\n" ); - m_ppath = NULL; - return; - } - - Vector nextPos = pevTarget->origin; - nextPos.z += m_height; - - Vector look = nextPos; - look.z -= m_height; - m_ppath->LookAhead( &look, m_length, 0 ); - look.z += m_height; - - pev->angles = UTIL_VecToAngles( look - nextPos ); - // The train actually points west - pev->angles.y += 180; - - if ( pev->spawnflags & SF_TRACKTRAIN_NOPITCH ) - pev->angles.x = 0; - UTIL_SetOrigin( pev, nextPos ); - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - pev->speed = m_startSpeed; - - UpdateSound(); -} - - -void CFuncTrackTrain :: NearestPath( void ) -{ - CBaseEntity *pTrack = NULL; - CBaseEntity *pNearest = NULL; - float dist, closest; - - closest = 1024; - - while ((pTrack = UTIL_FindEntityInSphere( pTrack, pev->origin, 1024 )) != NULL) - { - // filter out non-tracks - if ( !(pTrack->pev->flags & (FL_CLIENT|FL_MONSTER)) && FClassnameIs( pTrack->pev, "path_track" ) ) - { - dist = (pev->origin - pTrack->pev->origin).Length(); - if ( dist < closest ) - { - closest = dist; - pNearest = pTrack; - } - } - } - - if ( !pNearest ) - { - ALERT( at_console, "Can't find a nearby track !!!\n" ); - SetThink(NULL); - return; - } - - ALERT( at_aiconsole, "TRAIN: %s, Nearest track is %s\n", STRING(pev->targetname), STRING(pNearest->pev->targetname) ); - // If I'm closer to the next path_track on this path, then it's my real path - pTrack = ((CPathTrack *)pNearest)->GetNext(); - if ( pTrack ) - { - if ( (pev->origin - pTrack->pev->origin).Length() < (pev->origin - pNearest->pev->origin).Length() ) - pNearest = pTrack; - } - - m_ppath = (CPathTrack *)pNearest; - - if ( pev->speed != 0 ) - { - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Next ); - } -} - - -void CFuncTrackTrain::OverrideReset( void ) -{ - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::NearestPath ); -} - - -CFuncTrackTrain *CFuncTrackTrain::Instance( edict_t *pent ) -{ - if ( FClassnameIs( pent, "func_tracktrain" ) ) - return (CFuncTrackTrain *)GET_PRIVATE(pent); - return NULL; -} - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving platforms that players can ride. -The targets origin specifies the min point of the train at each corner. -The train spawns at the first target it is pointing at. -If the train is the target of a button or trigger, it will not begin moving until activated. -speed default 100 -dmg default 2 -sounds -1) ratchet metal -*/ - -void CFuncTrackTrain :: Spawn( void ) -{ - if ( pev->speed == 0 ) - m_speed = 100; - else - m_speed = pev->speed; - - pev->speed = 0; - pev->velocity = g_vecZero; - pev->avelocity = g_vecZero; - pev->impulse = static_cast(m_speed); - - m_dir = 1; - - if ( FStringNull(pev->target) ) - ALERT( at_console, "FuncTrain with no target" ); - - if ( pev->spawnflags & SF_TRACKTRAIN_PASSABLE ) - pev->solid = SOLID_NOT; - else - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - // Cache off placed origin for train controls - pev->oldorigin = pev->origin; - - m_controlMins = pev->mins; - m_controlMaxs = pev->maxs; - m_controlMaxs.z += 72; -// start trains on the next frame, to make sure their targets have had -// a chance to spawn/activate - NextThink( pev->ltime + 0.1, FALSE ); - SetThink( &CFuncTrackTrain::Find ); - Precache(); -} - -void CFuncTrackTrain :: Precache( void ) -{ - if (m_flVolume == 0.0) - m_flVolume = 1.0; - - switch (m_sounds) - { - default: - // no sound - pev->noise = 0; - break; - case 1: PRECACHE_SOUND("plats/ttrain1.wav"); pev->noise = MAKE_STRING("plats/ttrain1.wav");break; - case 2: PRECACHE_SOUND("plats/ttrain2.wav"); pev->noise = MAKE_STRING("plats/ttrain2.wav");break; - case 3: PRECACHE_SOUND("plats/ttrain3.wav"); pev->noise = MAKE_STRING("plats/ttrain3.wav");break; - case 4: PRECACHE_SOUND("plats/ttrain4.wav"); pev->noise = MAKE_STRING("plats/ttrain4.wav");break; - case 5: PRECACHE_SOUND("plats/ttrain6.wav"); pev->noise = MAKE_STRING("plats/ttrain6.wav");break; - case 6: PRECACHE_SOUND("plats/ttrain7.wav"); pev->noise = MAKE_STRING("plats/ttrain7.wav");break; - } - - PRECACHE_SOUND("plats/ttrain_brake1.wav"); - PRECACHE_SOUND("plats/ttrain_start1.wav"); - - m_usAdjustPitch = PRECACHE_EVENT( 1, "events/train.sc" ); -} - -// This class defines the volume of space that the player must stand in to control the train -class CFuncTrainControls : public CBaseEntity -{ -public: - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - void Spawn( void ); - void EXPORT Find( void ); -}; -LINK_ENTITY_TO_CLASS( func_traincontrols, CFuncTrainControls ); - - -void CFuncTrainControls :: Find( void ) -{ - edict_t *pTarget = NULL; - - do - { - pTarget = FIND_ENTITY_BY_TARGETNAME( pTarget, STRING(pev->target) ); - } while ( !FNullEnt(pTarget) && !FClassnameIs(pTarget, "func_tracktrain") ); - - if ( FNullEnt( pTarget ) ) - { - ALERT( at_console, "No train %s\n", STRING(pev->target) ); - return; - } - - CFuncTrackTrain *ptrain = CFuncTrackTrain::Instance(pTarget); - ptrain->SetControls( pev ); - UTIL_Remove( this ); -} - - -void CFuncTrainControls :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL( ENT(pev), STRING(pev->model) ); - - UTIL_SetSize( pev, pev->mins, pev->maxs ); - UTIL_SetOrigin( pev, pev->origin ); - - SetThink( &CFuncTrainControls::Find ); - pev->nextthink = gpGlobals->time; -} - - - -// ---------------------------------------------------------------------------- -// -// Track changer / Train elevator -// -// ---------------------------------------------------------------------------- - -#define SF_TRACK_ACTIVATETRAIN 0x00000001 -#define SF_TRACK_RELINK 0x00000002 -#define SF_TRACK_ROTMOVE 0x00000004 -#define SF_TRACK_STARTBOTTOM 0x00000008 -#define SF_TRACK_DONT_MOVE 0x00000010 - -// -// This entity is a rotating/moving platform that will carry a train to a new track. -// It must be larger in X-Y planar area than the train, since it must contain the -// train within these dimensions in order to operate when the train is near it. -// - -typedef enum { TRAIN_SAFE, TRAIN_BLOCKING, TRAIN_FOLLOWING } TRAIN_CODE; - -class CFuncTrackChange : public CFuncPlatRot -{ -public: - void Spawn( void ); - void Precache( void ); - -// virtual void Blocked( void ); - virtual void EXPORT GoUp( void ); - virtual void EXPORT GoDown( void ); - - void KeyValue( KeyValueData* pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Find( void ); - TRAIN_CODE EvaluateTrain( CPathTrack *pcurrent ); - void UpdateTrain( Vector &dest ); - virtual void HitBottom( void ); - virtual void HitTop( void ); - void Touch( CBaseEntity *pOther ); - virtual void UpdateAutoTargets( int toggleState ); - virtual BOOL IsTogglePlat( void ) { return TRUE; } - - void DisableUse( void ) { m_use = 0; } - void EnableUse( void ) { m_use = 1; } - int UseEnabled( void ) { return m_use; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void OverrideReset( void ); - - - CPathTrack *m_trackTop; - CPathTrack *m_trackBottom; - - CFuncTrackTrain *m_train; - - int m_trackTopName; - int m_trackBottomName; - int m_trainName; - TRAIN_CODE m_code; - int m_targetState; - int m_use; -}; -LINK_ENTITY_TO_CLASS( func_trackchange, CFuncTrackChange ); - -TYPEDESCRIPTION CFuncTrackChange::m_SaveData[] = -{ - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTop, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottom, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_train, FIELD_CLASSPTR ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackTopName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trackBottomName, FIELD_STRING ), - DEFINE_GLOBAL_FIELD( CFuncTrackChange, m_trainName, FIELD_STRING ), - DEFINE_FIELD( CFuncTrackChange, m_code, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_targetState, FIELD_INTEGER ), - DEFINE_FIELD( CFuncTrackChange, m_use, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CFuncTrackChange, CFuncPlatRot ); - -void CFuncTrackChange :: Spawn( void ) -{ - Setup(); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - m_vecPosition2.z = pev->origin.z; - - SetupRotation(); - - if ( FBitSet( pev->spawnflags, SF_TRACK_STARTBOTTOM ) ) - { - UTIL_SetOrigin (pev, m_vecPosition2); - m_toggle_state = TS_AT_BOTTOM; - pev->angles = m_start; - m_targetState = TS_AT_TOP; - } - else - { - UTIL_SetOrigin (pev, m_vecPosition1); - m_toggle_state = TS_AT_TOP; - pev->angles = m_end; - m_targetState = TS_AT_BOTTOM; - } - - EnableUse(); - pev->nextthink = pev->ltime + 2.0; - SetThink( &CFuncTrackChange::Find ); - Precache(); -} - -void CFuncTrackChange :: Precache( void ) -{ - // Can't trigger sound - PRECACHE_SOUND( "buttons/button11.wav" ); - - CFuncPlatRot::Precache(); -} - - -// UNDONE: Filter touches before re-evaluating the train. -void CFuncTrackChange :: Touch( CBaseEntity *pOther ) -{ -#if 0 - TRAIN_CODE code; - entvars_t *pevToucher = pOther->pev; -#endif -} - - - -void CFuncTrackChange :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "train") ) - { - m_trainName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "toptrack") ) - { - m_trackTopName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "bottomtrack") ) - { - m_trackBottomName = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CFuncPlatRot::KeyValue( pkvd ); // Pass up to base class - } -} - - -void CFuncTrackChange::OverrideReset( void ) -{ - pev->nextthink = pev->ltime + 1.0; - SetThink( &CFuncTrackChange::Find ); -} - -void CFuncTrackChange :: Find( void ) -{ - // Find track entities - edict_t *target; - - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackTopName) ); - if ( !FNullEnt(target) ) - { - m_trackTop = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trackBottomName) ); - if ( !FNullEnt(target) ) - { - m_trackBottom = CPathTrack::Instance( target ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - if ( !FNullEnt(target) ) - { - m_train = CFuncTrackTrain::Instance( FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ) ); - if ( !m_train ) - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - return; - } - Vector center = (pev->absmin + pev->absmax) * 0.5; - m_trackBottom = m_trackBottom->Nearest( center ); - m_trackTop = m_trackTop->Nearest( center ); - UpdateAutoTargets( m_toggle_state ); - SetThink( NULL ); - return; - } - else - { - ALERT( at_error, "Can't find train for track change! %s\n", STRING(m_trainName) ); - target = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_trainName) ); - } - } - else - ALERT( at_error, "Can't find bottom track for track change! %s\n", STRING(m_trackBottomName) ); - } - else - ALERT( at_error, "Can't find top track for track change! %s\n", STRING(m_trackTopName) ); -} - - - -TRAIN_CODE CFuncTrackChange :: EvaluateTrain( CPathTrack *pcurrent ) -{ - // Go ahead and work, we don't have anything to switch, so just be an elevator - if ( !pcurrent || !m_train ) - return TRAIN_SAFE; - - if ( m_train->m_ppath == pcurrent || (pcurrent->m_pprevious && m_train->m_ppath == pcurrent->m_pprevious) || - (pcurrent->m_pnext && m_train->m_ppath == pcurrent->m_pnext) ) - { - if ( m_train->pev->speed != 0 ) - return TRAIN_BLOCKING; - - Vector dist = pev->origin - m_train->pev->origin; - float length = dist.Length2D(); - if ( length < m_train->m_length ) // Empirically determined close distance - return TRAIN_FOLLOWING; - else if ( length > (150 + m_train->m_length) ) - return TRAIN_SAFE; - - return TRAIN_BLOCKING; - } - - return TRAIN_SAFE; -} - - -void CFuncTrackChange :: UpdateTrain( Vector &dest ) -{ - float time = (pev->nextthink - pev->ltime); - - m_train->pev->velocity = pev->velocity; - m_train->pev->avelocity = pev->avelocity; - m_train->NextThink( m_train->pev->ltime + time, FALSE ); - - // Attempt at getting the train to rotate properly around the origin of the trackchange - if ( time <= 0 ) - return; - - Vector offset = m_train->pev->origin - pev->origin; - Vector delta = dest - pev->angles; - // Transform offset into local coordinates - UTIL_MakeInvVectors( delta, gpGlobals ); - Vector local; - local.x = DotProduct( offset, gpGlobals->v_forward ); - local.y = DotProduct( offset, gpGlobals->v_right ); - local.z = DotProduct( offset, gpGlobals->v_up ); - - local = local - offset; - m_train->pev->velocity = pev->velocity + (local * (1.0/time)); -} - -void CFuncTrackChange :: GoDown( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitBottom may get called during CFuncPlat::GoDown(), so set up for that - // before you call GoDown() - - UpdateAutoTargets( TS_GOING_DOWN ); - // If ROTMOVE, move & rotate - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - m_toggle_state = TS_GOING_DOWN; - AngularMove( m_start, pev->speed ); - } - else - { - CFuncPlat :: GoDown(); - SetMoveDone( &CFuncTrackChange::CallHitBottom ); - RotMove( m_start, pev->nextthink - pev->ltime ); - } - // Otherwise, rotate first, move second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_start ); - m_train->m_ppath = NULL; - } -} - - -// -// Platform is at bottom, now starts moving up -// -void CFuncTrackChange :: GoUp( void ) -{ - if ( m_code == TRAIN_BLOCKING ) - return; - - // HitTop may get called during CFuncPlat::GoUp(), so set up for that - // before you call GoUp(); - - UpdateAutoTargets( TS_GOING_UP ); - if ( FBitSet( pev->spawnflags, SF_TRACK_DONT_MOVE ) ) - { - m_toggle_state = TS_GOING_UP; - SetMoveDone( &CFuncTrackChange::CallHitTop ); - AngularMove( m_end, pev->speed ); - } - else - { - // If ROTMOVE, move & rotate - CFuncPlat :: GoUp(); - SetMoveDone( &CFuncTrackChange::CallHitTop ); - RotMove( m_end, pev->nextthink - pev->ltime ); - } - - // Otherwise, move first, rotate second - - // If the train is moving with the platform, update it - if ( m_code == TRAIN_FOLLOWING ) - { - UpdateTrain( m_end ); - m_train->m_ppath = NULL; - } -} - - -// Normal track change -void CFuncTrackChange :: UpdateAutoTargets( int toggleState ) -{ - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( toggleState == TS_AT_TOP ) - ClearBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackTop->pev->spawnflags, SF_PATH_DISABLED ); - - if ( toggleState == TS_AT_BOTTOM ) - ClearBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); - else - SetBits( m_trackBottom->pev->spawnflags, SF_PATH_DISABLED ); -} - - -void CFuncTrackChange :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( m_toggle_state != TS_AT_TOP && m_toggle_state != TS_AT_BOTTOM ) - return; - - // If train is in "safe" area, but not on the elevator, play alarm sound - if ( m_toggle_state == TS_AT_TOP ) - m_code = EvaluateTrain( m_trackTop ); - else if ( m_toggle_state == TS_AT_BOTTOM ) - m_code = EvaluateTrain( m_trackBottom ); - else - m_code = TRAIN_BLOCKING; - if ( m_code == TRAIN_BLOCKING ) - { - // Play alarm and return - EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/button11.wav", 1, ATTN_NORM); - return; - } - - // Otherwise, it's safe to move - // If at top, go down - // at bottom, go up - - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitBottom( void ) -{ - CFuncPlatRot :: HitBottom(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackBottom ); - } - SetThink( NULL ); - pev->nextthink = -1; - - UpdateAutoTargets( m_toggle_state ); - - EnableUse(); -} - - -// -// Platform has hit bottom. Stops and waits forever. -// -void CFuncTrackChange :: HitTop( void ) -{ - CFuncPlatRot :: HitTop(); - if ( m_code == TRAIN_FOLLOWING ) - { -// UpdateTrain(); - m_train->SetTrack( m_trackTop ); - } - - // Don't let the plat go back down - SetThink( NULL ); - pev->nextthink = -1; - UpdateAutoTargets( m_toggle_state ); - EnableUse(); -} - - - -class CFuncTrackAuto : public CFuncTrackChange -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void UpdateAutoTargets( int toggleState ); -}; - -LINK_ENTITY_TO_CLASS( func_trackautochange, CFuncTrackAuto ); - -// Auto track change -void CFuncTrackAuto :: UpdateAutoTargets( int toggleState ) -{ - CPathTrack *pTarget, *pNextTarget; - - if ( !m_trackTop || !m_trackBottom ) - return; - - if ( m_targetState == TS_AT_TOP ) - { - pTarget = m_trackTop->GetNext(); - pNextTarget = m_trackBottom->GetNext(); - } - else - { - pTarget = m_trackBottom->GetNext(); - pNextTarget = m_trackTop->GetNext(); - } - if ( pTarget ) - { - ClearBits( pTarget->pev->spawnflags, SF_PATH_DISABLED ); - if ( m_code == TRAIN_FOLLOWING && m_train && m_train->pev->speed == 0 ) - m_train->Use( this, this, USE_ON, 0 ); - } - - if ( pNextTarget ) - SetBits( pNextTarget->pev->spawnflags, SF_PATH_DISABLED ); - -} - - -void CFuncTrackAuto :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CPathTrack *pTarget; - - if ( !UseEnabled() ) - return; - - if ( m_toggle_state == TS_AT_TOP ) - pTarget = m_trackTop; - else if ( m_toggle_state == TS_AT_BOTTOM ) - pTarget = m_trackBottom; - else - pTarget = NULL; - - if ( FClassnameIs( pActivator->pev, "func_tracktrain" ) ) - { - m_code = EvaluateTrain( pTarget ); - // Safe to fire? - if ( m_code == TRAIN_FOLLOWING && m_toggle_state != m_targetState ) - { - DisableUse(); - if (m_toggle_state == TS_AT_TOP) - GoDown(); - else - GoUp(); - } - } - else - { - if ( pTarget ) - pTarget = pTarget->GetNext(); - if ( pTarget && m_train->m_ppath != pTarget && ShouldToggle( useType, m_targetState ) ) - { - if ( m_targetState == TS_AT_TOP ) - m_targetState = TS_AT_BOTTOM; - else - m_targetState = TS_AT_TOP; - } - - UpdateAutoTargets( m_targetState ); - } -} - - -// ---------------------------------------------------------- -// -// -// pev->speed is the travel speed -// pev->health is current health -// pev->max_health is the amount to reset to each time it starts - -#define FGUNTARGET_START_ON 0x0001 - -class CGunTarget : public CBaseMonster -{ -public: - void Spawn( void ); - void Activate( void ); - void EXPORT Next( void ); - void EXPORT Start( void ); - void EXPORT Wait( void ); - void Stop( void ); - - int BloodColor( void ) { return DONT_BLEED; } - int Classify( void ) { return CLASS_MACHINE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - Vector BodyTarget( const Vector &posSrc ) { return pev->origin; } - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - BOOL m_on; -}; - - -LINK_ENTITY_TO_CLASS( func_guntarget, CGunTarget ); - -TYPEDESCRIPTION CGunTarget::m_SaveData[] = -{ - DEFINE_FIELD( CGunTarget, m_on, FIELD_BOOLEAN ), -}; - -IMPLEMENT_SAVERESTORE( CGunTarget, CBaseMonster ); - - -void CGunTarget::Spawn( void ) -{ - pev->solid = SOLID_BSP; - pev->movetype = MOVETYPE_PUSH; - - UTIL_SetOrigin(pev, pev->origin); - SET_MODEL(ENT(pev), STRING(pev->model) ); - - if ( pev->speed == 0 ) - pev->speed = 100; - - // Don't take damage until "on" - pev->takedamage = DAMAGE_NO; - pev->flags |= FL_MONSTER; - - m_on = FALSE; - pev->max_health = pev->health; - - if ( pev->spawnflags & FGUNTARGET_START_ON ) - { - SetThink( &CGunTarget::Start ); - pev->nextthink = pev->ltime + 0.3; - } -} - - -void CGunTarget::Activate( void ) -{ - CBaseEntity *pTarg; - - // now find our next target - pTarg = GetNextTarget(); - if ( pTarg ) - { - m_hTargetEnt = pTarg; - UTIL_SetOrigin( pev, pTarg->pev->origin - (pev->mins + pev->maxs) * 0.5 ); - } -} - - -void CGunTarget::Start( void ) -{ - Use( this, this, USE_ON, 0 ); -} - - -void CGunTarget::Next( void ) -{ - SetThink( NULL ); - - m_hTargetEnt = GetNextTarget(); - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - SetMoveDone( &CGunTarget::Wait ); - LinearMove( pTarget->pev->origin - (pev->mins + pev->maxs) * 0.5, pev->speed ); -} - - -void CGunTarget::Wait( void ) -{ - CBaseEntity *pTarget = m_hTargetEnt; - - if ( !pTarget ) - { - Stop(); - return; - } - - // Fire the pass target if there is one - if ( pTarget->pev->message ) - { - FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( pTarget->pev->spawnflags, SF_CORNER_FIREONCE ) ) - pTarget->pev->message = 0; - } - - m_flWait = pTarget->GetDelay(); - - pev->target = pTarget->pev->target; - SetThink( &CGunTarget::Next ); - if (m_flWait != 0) - {// -1 wait will wait forever! - pev->nextthink = pev->ltime + m_flWait; - } - else - { - Next();// do it RIGHT now! - } -} - - -void CGunTarget::Stop( void ) -{ - pev->velocity = g_vecZero; - pev->nextthink = 0; - pev->takedamage = DAMAGE_NO; -} - - -int CGunTarget::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if ( pev->health > 0 ) - { - pev->health -= flDamage; - if ( pev->health <= 0 ) - { - pev->health = 0; - Stop(); - if ( pev->message ) - FireTargets( STRING(pev->message), this, this, USE_TOGGLE, 0 ); - } - } - return 0; -} - - -void CGunTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_on ) ) - return; - - if ( m_on ) - { - Stop(); - } - else - { - pev->takedamage = DAMAGE_AIM; - m_hTargetEnt = GetNextTarget(); - if ( m_hTargetEnt == 0 ) - return; - pev->health = pev->max_health; - Next(); - } -} - - - diff --git a/sdk/dlls/player.cpp b/sdk/dlls/player.cpp deleted file mode 100644 index 654e456..0000000 --- a/sdk/dlls/player.cpp +++ /dev/null @@ -1,4881 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== player.cpp ======================================================== - - functions dealing with the player - -*/ - -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "shake.h" -#include "decals.h" -#include "gamerules.h" -#include "game.h" -#include "pm_shared.h" -#include "hltv.h" - -// #define DUCKFIX - -extern DLL_GLOBAL ULONG g_ulModelIndexPlayer; -extern DLL_GLOBAL BOOL g_fGameOver; -extern DLL_GLOBAL BOOL g_fDrawLines; -int gEvilImpulse101; -extern DLL_GLOBAL int g_iSkillLevel, gDisplayTitle; - - -BOOL gInitHUD = TRUE; - -extern void CopyToBodyQue(entvars_t* pev); -extern void respawn(entvars_t *pev, BOOL fCopyCorpse); -extern Vector VecBModelOrigin(entvars_t *pevBModel ); -extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ); - -// the world node graph -extern CGraph WorldGraph; - -#define TRAIN_ACTIVE 0x80 -#define TRAIN_NEW 0xc0 -#define TRAIN_OFF 0x00 -#define TRAIN_NEUTRAL 0x01 -#define TRAIN_SLOW 0x02 -#define TRAIN_MEDIUM 0x03 -#define TRAIN_FAST 0x04 -#define TRAIN_BACK 0x05 - -#define FLASH_DRAIN_TIME 1.2 //100 units/3 minutes -#define FLASH_CHARGE_TIME 0.2 // 100 units/20 seconds (seconds per unit) - -// Global Savedata for player -TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] = -{ - DEFINE_FIELD( CBasePlayer, m_flFlashLightTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_iFlashBattery, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_afButtonLast, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonPressed, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_afButtonReleased, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgItems, FIELD_INTEGER, MAX_ITEMS ), - DEFINE_FIELD( CBasePlayer, m_afPhysicsFlags, FIELD_INTEGER ), - - DEFINE_FIELD( CBasePlayer, m_flTimeStepSound, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flTimeWeaponIdle, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flSwimTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flDuckTime, FIELD_TIME ), - DEFINE_FIELD( CBasePlayer, m_flWallJumpTime, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_flSuitUpdate, FIELD_TIME ), - DEFINE_ARRAY( CBasePlayer, m_rgSuitPlayList, FIELD_INTEGER, CSUITPLAYLIST ), - DEFINE_FIELD( CBasePlayer, m_iSuitPlayNext, FIELD_INTEGER ), - DEFINE_ARRAY( CBasePlayer, m_rgiSuitNoRepeat, FIELD_INTEGER, CSUITNOREPEAT ), - DEFINE_ARRAY( CBasePlayer, m_rgflSuitNoRepeatTime, FIELD_TIME, CSUITNOREPEAT ), - DEFINE_FIELD( CBasePlayer, m_lastDamageAmount, FIELD_INTEGER ), - - DEFINE_ARRAY( CBasePlayer, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CBasePlayer, m_pActiveItem, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayer, m_pLastItem, FIELD_CLASSPTR ), - - DEFINE_ARRAY( CBasePlayer, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_FIELD( CBasePlayer, m_idrowndmg, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_idrownrestored, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_tSneaking, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_iTrain, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_bitsHUDDamage, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_flFallVelocity, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayer, m_iTargetVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponVolume, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iExtraSoundTypes, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iWeaponFlash, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_fLongJump, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_fInitHUD, FIELD_BOOLEAN ), - DEFINE_FIELD( CBasePlayer, m_tbdPrev, FIELD_TIME ), - - DEFINE_FIELD( CBasePlayer, m_pTank, FIELD_EHANDLE ), - DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ), - - //DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games - //DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games - //DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ), - //DEFINE_FIELD( CBasePlayer, m_fKnownItem, FIELD_INTEGER ), // reset to zero on load - //DEFINE_FIELD( CBasePlayer, m_iPlayerSound, FIELD_INTEGER ), // Don't restore, set in Precache() - //DEFINE_FIELD( CBasePlayer, m_pentSndLast, FIELD_EDICT ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_flSndRoomtype, FIELD_FLOAT ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_flSndRange, FIELD_FLOAT ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_fNewAmmo, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_flgeigerRange, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_flgeigerDelay, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_igeigerRangePrev, FIELD_FLOAT ), // Don't restore, reset in Precache() - //DEFINE_FIELD( CBasePlayer, m_iStepLeft, FIELD_INTEGER ), // Don't need to restore - //DEFINE_ARRAY( CBasePlayer, m_szTextureName, FIELD_CHARACTER, CBTEXTURENAMEMAX ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_chTextureType, FIELD_CHARACTER ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_fNoPlayerSound, FIELD_BOOLEAN ), // Don't need to restore, debug - //DEFINE_FIELD( CBasePlayer, m_iUpdateTime, FIELD_INTEGER ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_iClientHealth, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_iClientBattery, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_iClientHideHUD, FIELD_INTEGER ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_fWeapon, FIELD_BOOLEAN ), // Don't restore, client needs reset - //DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't restore, depends on server message after spawning and only matters in multiplayer - //DEFINE_FIELD( CBasePlayer, m_vecAutoAim, FIELD_VECTOR ), // Don't save/restore - this is recomputed - //DEFINE_ARRAY( CBasePlayer, m_rgAmmoLast, FIELD_INTEGER, MAX_AMMO_SLOTS ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_fOnTarget, FIELD_BOOLEAN ), // Don't need to restore - //DEFINE_FIELD( CBasePlayer, m_nCustomSprayFrames, FIELD_INTEGER ), // Don't need to restore - -}; - - -int giPrecacheGrunt = 0; -int gmsgShake = 0; -int gmsgFade = 0; -int gmsgSelAmmo = 0; -int gmsgFlashlight = 0; -int gmsgFlashBattery = 0; -int gmsgResetHUD = 0; -int gmsgInitHUD = 0; -int gmsgShowGameTitle = 0; -int gmsgCurWeapon = 0; -int gmsgHealth = 0; -int gmsgDamage = 0; -int gmsgBattery = 0; -int gmsgTrain = 0; -int gmsgLogo = 0; -int gmsgWeaponList = 0; -int gmsgAmmoX = 0; -int gmsgHudText = 0; -int gmsgDeathMsg = 0; -int gmsgScoreInfo = 0; -int gmsgTeamInfo = 0; -int gmsgTeamScore = 0; -int gmsgGameMode = 0; -int gmsgMOTD = 0; -int gmsgServerName = 0; -int gmsgAmmoPickup = 0; -int gmsgWeapPickup = 0; -int gmsgItemPickup = 0; -int gmsgHideWeapon = 0; -int gmsgSetCurWeap = 0; -int gmsgSayText = 0; -int gmsgTextMsg = 0; -int gmsgSetFOV = 0; -int gmsgShowMenu = 0; -int gmsgGeigerRange = 0; -int gmsgTeamNames = 0; - -int gmsgStatusText = 0; -int gmsgStatusValue = 0; - - - -void LinkUserMessages( void ) -{ - // Already taken care of? - if ( gmsgSelAmmo ) - { - return; - } - - gmsgSelAmmo = REG_USER_MSG("SelAmmo", sizeof(SelAmmo)); - gmsgCurWeapon = REG_USER_MSG("CurWeapon", 3); - gmsgGeigerRange = REG_USER_MSG("Geiger", 1); - gmsgFlashlight = REG_USER_MSG("Flashlight", 2); - gmsgFlashBattery = REG_USER_MSG("FlashBat", 1); - gmsgHealth = REG_USER_MSG( "Health", 1 ); - gmsgDamage = REG_USER_MSG( "Damage", 12 ); - gmsgBattery = REG_USER_MSG( "Battery", 2); - gmsgTrain = REG_USER_MSG( "Train", 1); - //gmsgHudText = REG_USER_MSG( "HudTextPro", -1 ); - gmsgHudText = REG_USER_MSG( "HudText", -1 ); // we don't use the message but 3rd party addons may! - gmsgSayText = REG_USER_MSG( "SayText", -1 ); - gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); - gmsgWeaponList = REG_USER_MSG("WeaponList", -1); - gmsgResetHUD = REG_USER_MSG("ResetHUD", 1); // called every respawn - gmsgInitHUD = REG_USER_MSG("InitHUD", 0 ); // called every time a new player joins the server - gmsgShowGameTitle = REG_USER_MSG("GameTitle", 1); - gmsgDeathMsg = REG_USER_MSG( "DeathMsg", -1 ); - gmsgScoreInfo = REG_USER_MSG( "ScoreInfo", 9 ); - gmsgTeamInfo = REG_USER_MSG( "TeamInfo", -1 ); // sets the name of a player's team - gmsgTeamScore = REG_USER_MSG( "TeamScore", -1 ); // sets the score of a team on the scoreboard - gmsgGameMode = REG_USER_MSG( "GameMode", 1 ); - gmsgMOTD = REG_USER_MSG( "MOTD", -1 ); - gmsgServerName = REG_USER_MSG( "ServerName", -1 ); - gmsgAmmoPickup = REG_USER_MSG( "AmmoPickup", 2 ); - gmsgWeapPickup = REG_USER_MSG( "WeapPickup", 1 ); - gmsgItemPickup = REG_USER_MSG( "ItemPickup", -1 ); - gmsgHideWeapon = REG_USER_MSG( "HideWeapon", 1 ); - gmsgSetFOV = REG_USER_MSG( "SetFOV", 1 ); - gmsgShowMenu = REG_USER_MSG( "ShowMenu", -1 ); - gmsgShake = REG_USER_MSG("ScreenShake", sizeof(ScreenShake)); - gmsgFade = REG_USER_MSG("ScreenFade", sizeof(ScreenFade)); - gmsgAmmoX = REG_USER_MSG("AmmoX", 2); - gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 ); - - gmsgStatusText = REG_USER_MSG("StatusText", -1); - gmsgStatusValue = REG_USER_MSG("StatusValue", 3); - -} - -LINK_ENTITY_TO_CLASS( player, CBasePlayer ); - - - -void CBasePlayer :: Pain( void ) -{ - float flRndSound;//sound randomizer - - flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); -} - -/* - * - */ -Vector VecVelocityForDamage(float flDamage) -{ - Vector vec(RANDOM_FLOAT(-100,100), RANDOM_FLOAT(-100,100), RANDOM_FLOAT(200,300)); - - if (flDamage > -50) - vec = vec * 0.7; - else if (flDamage > -200) - vec = vec * 2; - else - vec = vec * 10; - - return vec; -} - -#if 0 /* -static void ThrowGib(entvars_t *pev, char *szGibModel, float flDamage) -{ - edict_t *pentNew = CREATE_ENTITY(); - entvars_t *pevNew = VARS(pentNew); - - pevNew->origin = pev->origin; - SET_MODEL(ENT(pevNew), szGibModel); - UTIL_SetSize(pevNew, g_vecZero, g_vecZero); - - pevNew->velocity = VecVelocityForDamage(flDamage); - pevNew->movetype = MOVETYPE_BOUNCE; - pevNew->solid = SOLID_NOT; - pevNew->avelocity.x = RANDOM_FLOAT(0,600); - pevNew->avelocity.y = RANDOM_FLOAT(0,600); - pevNew->avelocity.z = RANDOM_FLOAT(0,600); - CHANGE_METHOD(ENT(pevNew), em_think, SUB_Remove); - pevNew->ltime = gpGlobals->time; - pevNew->nextthink = gpGlobals->time + RANDOM_FLOAT(10,20); - pevNew->frame = 0; - pevNew->flags = 0; -} - - -static void ThrowHead(entvars_t *pev, char *szGibModel, floatflDamage) -{ - SET_MODEL(ENT(pev), szGibModel); - pev->frame = 0; - pev->nextthink = -1; - pev->movetype = MOVETYPE_BOUNCE; - pev->takedamage = DAMAGE_NO; - pev->solid = SOLID_NOT; - pev->view_ofs = Vector(0,0,8); - UTIL_SetSize(pev, Vector(-16,-16,0), Vector(16,16,56)); - pev->velocity = VecVelocityForDamage(flDamage); - pev->avelocity = RANDOM_FLOAT(-1,1) * Vector(0,600,0); - pev->origin.z -= 24; - ClearBits(pev->flags, FL_ONGROUND); -} - - -*/ -#endif - -int TrainSpeed(int iSpeed, int iMax) -{ - float fSpeed, fMax; - int iRet = 0; - - fMax = (float)iMax; - fSpeed = iSpeed; - - fSpeed = fSpeed/fMax; - - if (iSpeed < 0) - iRet = TRAIN_BACK; - else if (iSpeed == 0) - iRet = TRAIN_NEUTRAL; - else if (fSpeed < 0.33) - iRet = TRAIN_SLOW; - else if (fSpeed < 0.66) - iRet = TRAIN_MEDIUM; - else - iRet = TRAIN_FAST; - - return iRet; -} - -void CBasePlayer :: DeathSound( void ) -{ - // water death sounds - /* - if (pev->waterlevel == 3) - { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/h2odeath.wav", 1, ATTN_NONE); - return; - } - */ - - // temporarily using pain sounds for death sounds - switch (RANDOM_LONG(1,5)) - { - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain5.wav", 1, ATTN_NORM); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain6.wav", 1, ATTN_NORM); - break; - case 3: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_pain7.wav", 1, ATTN_NORM); - break; - } - - // play one of the suit death alarms - EMIT_GROUPNAME_SUIT(ENT(pev), "HEV_DEAD"); -} - -// override takehealth -// bitsDamageType indicates type of damage healed. - -int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) -{ - return CBaseMonster :: TakeHealth (flHealth, bitsDamageType); - -} - -Vector CBasePlayer :: GetGunPosition( ) -{ -// UTIL_MakeVectors(pev->v_angle); -// m_HackedGunPos = pev->view_ofs; - Vector origin; - - origin = pev->origin + pev->view_ofs; - - return origin; -} - -//========================================================= -// TraceAttack -//========================================================= -void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( pev->takedamage ) - { - m_LastHitGroup = ptr->iHitgroup; - - switch ( ptr->iHitgroup ) - { - case HITGROUP_GENERIC: - break; - case HITGROUP_HEAD: - flDamage *= gSkillData.plrHead; - break; - case HITGROUP_CHEST: - flDamage *= gSkillData.plrChest; - break; - case HITGROUP_STOMACH: - flDamage *= gSkillData.plrStomach; - break; - case HITGROUP_LEFTARM: - case HITGROUP_RIGHTARM: - flDamage *= gSkillData.plrArm; - break; - case HITGROUP_LEFTLEG: - case HITGROUP_RIGHTLEG: - flDamage *= gSkillData.plrLeg; - break; - default: - break; - } - - SpawnBlood(ptr->vecEndPos, BloodColor(), flDamage);// a little surface blood. - TraceBleed( flDamage, vecDir, ptr, bitsDamageType ); - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); - } -} - -/* - Take some damage. - NOTE: each call to TakeDamage with bitsDamageType set to a time-based damage - type will cause the damage time countdown to be reset. Thus the ongoing effects of poison, radiation - etc are implemented with subsequent calls to TakeDamage using DMG_GENERIC. -*/ - -#define ARMOR_RATIO 0.2 // Armor Takes 80% of the damage -#define ARMOR_BONUS 0.5 // Each Point of Armor is work 1/x points of health - -int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // have suit diagnose the problem - ie: report damage type - int bitsDamage = bitsDamageType; - int ffound = TRUE; - int fmajor; - int fcritical; - int fTookDamage; - int ftrivial; - float flRatio; - float flBonus; - float flHealthPrev = pev->health; - - flBonus = ARMOR_BONUS; - flRatio = ARMOR_RATIO; - - if ( ( bitsDamageType & DMG_BLAST ) && g_pGameRules->IsMultiplayer() ) - { - // blasts damage armor more. - flBonus *= 2; - } - - // Already dead - if ( !IsAlive() ) - return 0; - // go take the damage first - - - CBaseEntity *pAttacker = CBaseEntity::Instance(pevAttacker); - - if ( !g_pGameRules->FPlayerCanTakeDamage( this, pAttacker ) ) - { - // Refuse the damage - return 0; - } - - // keep track of amount of damage last sustained - m_lastDamageAmount = static_cast(flDamage); - - // Armor. - if (pev->armorvalue && !(bitsDamageType & (DMG_FALL | DMG_DROWN)) )// armor doesn't protect against fall or drown damage! - { - float flNew = flDamage * flRatio; - - float flArmor; - - flArmor = (flDamage - flNew) * flBonus; - - // Does this use more armor than we have? - if (flArmor > pev->armorvalue) - { - flArmor = pev->armorvalue; - flArmor *= (1/flBonus); - flNew = flDamage - flArmor; - pev->armorvalue = 0; - } - else - pev->armorvalue -= flArmor; - - flDamage = flNew; - } - - // this cast to INT is critical!!! If a player ends up with 0.5 health, the engine will get that - // as an int (zero) and think the player is dead! (this will incite a clientside screentilt, etc) - fTookDamage = CBaseMonster::TakeDamage(pevInflictor, pevAttacker, (int)flDamage, bitsDamageType); - - // reset damage time countdown for each type of time based damage player just sustained - - { - for (int i = 0; i < CDMG_TIMEBASED; i++) - if (bitsDamageType & (DMG_PARALYZE << i)) - m_rgbTimeBasedDamage[i] = 0; - } - - // tell director about it - MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); - WRITE_BYTE ( 9 ); // command length in bytes - WRITE_BYTE ( DRC_CMD_EVENT ); // take damage event - WRITE_SHORT( ENTINDEX(this->edict()) ); // index number of primary entity - WRITE_SHORT( ENTINDEX(ENT(pevInflictor)) ); // index number of secondary entity - WRITE_LONG( 5 ); // eventflags (priority and flags) - MESSAGE_END(); - - - // how bad is it, doc? - - ftrivial = (pev->health > 75 || m_lastDamageAmount < 5); - fmajor = (m_lastDamageAmount > 25); - fcritical = (pev->health < 30); - - // handle all bits set in this damage message, - // let the suit give player the diagnosis - - // UNDONE: add sounds for types of damage sustained (ie: burn, shock, slash ) - - // UNDONE: still need to record damage and heal messages for the following types - - // DMG_BURN - // DMG_FREEZE - // DMG_BLAST - // DMG_SHOCK - - m_bitsDamageType |= bitsDamage; // Save this so we can report it to the client - m_bitsHUDDamage = -1; // make sure the damage bits get resent - - while (fTookDamage && (!ftrivial || (bitsDamage & DMG_TIMEBASED)) && ffound && bitsDamage) - { - ffound = FALSE; - - if (bitsDamage & DMG_CLUB) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - bitsDamage &= ~DMG_CLUB; - ffound = TRUE; - } - if (bitsDamage & (DMG_FALL | DMG_CRUSH)) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG5", FALSE, SUIT_NEXT_IN_30SEC); // major fracture - else - SetSuitUpdate("!HEV_DMG4", FALSE, SUIT_NEXT_IN_30SEC); // minor fracture - - bitsDamage &= ~(DMG_FALL | DMG_CRUSH); - ffound = TRUE; - } - - if (bitsDamage & DMG_BULLET) - { - if (m_lastDamageAmount > 5) - SetSuitUpdate("!HEV_DMG6", FALSE, SUIT_NEXT_IN_30SEC); // blood loss detected - //else - // SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_BULLET; - ffound = TRUE; - } - - if (bitsDamage & DMG_SLASH) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG1", FALSE, SUIT_NEXT_IN_30SEC); // major laceration - else - SetSuitUpdate("!HEV_DMG0", FALSE, SUIT_NEXT_IN_30SEC); // minor laceration - - bitsDamage &= ~DMG_SLASH; - ffound = TRUE; - } - - if (bitsDamage & DMG_SONIC) - { - if (fmajor) - SetSuitUpdate("!HEV_DMG2", FALSE, SUIT_NEXT_IN_1MIN); // internal bleeding - bitsDamage &= ~DMG_SONIC; - ffound = TRUE; - } - - if (bitsDamage & (DMG_POISON | DMG_PARALYZE)) - { - SetSuitUpdate("!HEV_DMG3", FALSE, SUIT_NEXT_IN_1MIN); // blood toxins detected - bitsDamage &= ~(DMG_POISON | DMG_PARALYZE); - ffound = TRUE; - } - - if (bitsDamage & DMG_ACID) - { - SetSuitUpdate("!HEV_DET1", FALSE, SUIT_NEXT_IN_1MIN); // hazardous chemicals detected - bitsDamage &= ~DMG_ACID; - ffound = TRUE; - } - - if (bitsDamage & DMG_NERVEGAS) - { - SetSuitUpdate("!HEV_DET0", FALSE, SUIT_NEXT_IN_1MIN); // biohazard detected - bitsDamage &= ~DMG_NERVEGAS; - ffound = TRUE; - } - - if (bitsDamage & DMG_RADIATION) - { - SetSuitUpdate("!HEV_DET2", FALSE, SUIT_NEXT_IN_1MIN); // radiation detected - bitsDamage &= ~DMG_RADIATION; - ffound = TRUE; - } - if (bitsDamage & DMG_SHOCK) - { - bitsDamage &= ~DMG_SHOCK; - ffound = TRUE; - } - } - - pev->punchangle.x = -2; - - if (fTookDamage && !ftrivial && fmajor && flHealthPrev >= 75) - { - // first time we take major damage... - // turn automedic on if not on - SetSuitUpdate("!HEV_MED1", FALSE, SUIT_NEXT_IN_30MIN); // automedic on - - // give morphine shot if not given recently - SetSuitUpdate("!HEV_HEAL7", FALSE, SUIT_NEXT_IN_30MIN); // morphine shot - } - - if (fTookDamage && !ftrivial && fcritical && flHealthPrev < 75) - { - - // already took major damage, now it's critical... - if (pev->health < 6) - SetSuitUpdate("!HEV_HLTH3", FALSE, SUIT_NEXT_IN_10MIN); // near death - else if (pev->health < 20) - SetSuitUpdate("!HEV_HLTH2", FALSE, SUIT_NEXT_IN_10MIN); // health critical - - // give critical health warnings - if (!RANDOM_LONG(0,3) && flHealthPrev < 50) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - - // if we're taking time based damage, warn about its continuing effects - if (fTookDamage && (bitsDamageType & DMG_TIMEBASED) && flHealthPrev < 75) - { - if (flHealthPrev < 50) - { - if (!RANDOM_LONG(0,3)) - SetSuitUpdate("!HEV_DMG7", FALSE, SUIT_NEXT_IN_5MIN); //seek medical attention - } - else - SetSuitUpdate("!HEV_HLTH1", FALSE, SUIT_NEXT_IN_10MIN); // health dropping - } - - return fTookDamage; -} - -//========================================================= -// PackDeadPlayerItems - call this when a player dies to -// pack up the appropriate weapons and ammo items, and to -// destroy anything that shouldn't be packed. -// -// This is pretty brute force :( -//========================================================= -void CBasePlayer::PackDeadPlayerItems( void ) -{ - int iWeaponRules; - int iAmmoRules; - int i; - CBasePlayerWeapon *rgpPackWeapons[ 20 ];// 20 hardcoded for now. How to determine exactly how many weapons we have? - int iPackAmmo[ MAX_AMMO_SLOTS + 1]; - int iPW = 0;// index into packweapons array - int iPA = 0;// index into packammo array - - memset(rgpPackWeapons, 0, sizeof(rgpPackWeapons) ); - memset(iPackAmmo, -1, sizeof(iPackAmmo) ); - - // get the game rules - iWeaponRules = g_pGameRules->DeadPlayerWeapons( this ); - iAmmoRules = g_pGameRules->DeadPlayerAmmo( this ); - - if ( iWeaponRules == GR_PLR_DROP_GUN_NO && iAmmoRules == GR_PLR_DROP_AMMO_NO ) - { - // nothing to pack. Remove the weapons and return. Don't call create on the box! - RemoveAllItems( TRUE ); - return; - } - -// go through all of the weapons and make a list of the ones to pack - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - // there's a weapon here. Should I pack it? - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - switch( iWeaponRules ) - { - case GR_PLR_DROP_GUN_ACTIVE: - if ( m_pActiveItem && pPlayerItem == m_pActiveItem ) - { - // this is the active item. Pack it. - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - } - break; - - case GR_PLR_DROP_GUN_ALL: - rgpPackWeapons[ iPW++ ] = (CBasePlayerWeapon *)pPlayerItem; - break; - - default: - break; - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - -// now go through ammo and make a list of which types to pack. - if ( iAmmoRules != GR_PLR_DROP_AMMO_NO ) - { - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( m_rgAmmo[ i ] > 0 ) - { - // player has some ammo of this type. - switch ( iAmmoRules ) - { - case GR_PLR_DROP_AMMO_ALL: - iPackAmmo[ iPA++ ] = i; - break; - - case GR_PLR_DROP_AMMO_ACTIVE: - if ( m_pActiveItem && i == m_pActiveItem->PrimaryAmmoIndex() ) - { - // this is the primary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - else if ( m_pActiveItem && i == m_pActiveItem->SecondaryAmmoIndex() ) - { - // this is the secondary ammo type for the active weapon - iPackAmmo[ iPA++ ] = i; - } - break; - - default: - break; - } - } - } - } - -// create a box to pack the stuff into. - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin, pev->angles, edict() ); - - pWeaponBox->pev->angles.x = 0;// don't let weaponbox tilt. - pWeaponBox->pev->angles.z = 0; - - pWeaponBox->SetThink( &CWeaponBox::Kill ); - pWeaponBox->pev->nextthink = gpGlobals->time + 120; - -// back these two lists up to their first elements - iPA = 0; - iPW = 0; - -// pack the ammo - while ( iPackAmmo[ iPA ] != -1 ) - { - pWeaponBox->PackAmmo( MAKE_STRING( CBasePlayerItem::AmmoInfoArray[ iPackAmmo[ iPA ] ].pszName ), m_rgAmmo[ iPackAmmo[ iPA ] ] ); - iPA++; - } - -// now pack all of the items in the lists - while ( rgpPackWeapons[ iPW ] ) - { - // weapon unhooked from the player. Pack it into der box. - pWeaponBox->PackWeapon( rgpPackWeapons[ iPW ] ); - - iPW++; - } - - pWeaponBox->pev->velocity = pev->velocity * 1.2;// weaponbox has player's velocity, then some. - - RemoveAllItems( TRUE );// now strip off everything that wasn't handled by the code above. -} - -void CBasePlayer::RemoveAllItems( BOOL removeSuit ) -{ - if (m_pActiveItem) - { - ResetAutoaim( ); - m_pActiveItem->Holster( ); - m_pActiveItem = NULL; - } - - m_pLastItem = NULL; - - if ( m_pTank != 0 ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - int i; - CBasePlayerItem *pPendingItem; - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - m_pActiveItem = m_rgpPlayerItems[i]; - while (m_pActiveItem) - { - pPendingItem = m_pActiveItem->m_pNext; - m_pActiveItem->Drop( ); - m_pActiveItem = pPendingItem; - } - m_rgpPlayerItems[i] = NULL; - } - m_pActiveItem = NULL; - - pev->viewmodel = 0; - pev->weaponmodel = 0; - - if ( removeSuit ) - pev->weapons = 0; - else - pev->weapons &= ~WEAPON_ALLWEAPONS; - - for ( i = 0; i < MAX_AMMO_SLOTS;i++) - m_rgAmmo[i] = 0; - - UpdateClientData(); - // send Selected Weapon Message to our client - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0); - WRITE_BYTE(0); - MESSAGE_END(); -} - -/* - * GLOBALS ASSUMED SET: g_ulModelIndexPlayer - * - * ENTITY_METHOD(PlayerDie) - */ -entvars_t *g_pevLastInflictor; // Set in combat.cpp. Used to pass the damage inflictor for death messages. - // Better solution: Add as parameter to all Killed() functions. - -void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) -{ - CSound *pSound; - - // Holster weapon immediately, to allow it to cleanup - if ( m_pActiveItem ) - m_pActiveItem->Holster( ); - - g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor ); - - if ( m_pTank != 0 ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - // this client isn't going to be thinking for a while, so reset the sound until they respawn - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( edict() ) ); - { - if ( pSound ) - { - pSound->Reset(); - } - } - - SetAnimation( PLAYER_DIE ); - - m_iRespawnFrames = 0; - - pev->modelindex = g_ulModelIndexPlayer; // don't use eyes - - pev->deadflag = DEAD_DYING; - pev->movetype = MOVETYPE_TOSS; - ClearBits( pev->flags, FL_ONGROUND ); - if (pev->velocity.z < 10) - pev->velocity.z += RANDOM_FLOAT(0,300); - - // clear out the suit message cache so we don't keep chattering - SetSuitUpdate(NULL, FALSE, 0); - - // send "health" update message to zero - m_iClientHealth = 0; - MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); - WRITE_BYTE( m_iClientHealth ); - MESSAGE_END(); - - // Tell Ammo Hud that the player is dead - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0XFF); - WRITE_BYTE(0xFF); - MESSAGE_END(); - - // reset FOV - pev->fov = m_iFOV = m_iClientFOV = 0; - - MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); - WRITE_BYTE(0); - MESSAGE_END(); - - - // UNDONE: Put this in, but add FFADE_PERMANENT and make fade time 8.8 instead of 4.12 - // UTIL_ScreenFade( edict(), Vector(128,0,0), 6, 15, 255, FFADE_OUT | FFADE_MODULATE ); - - if ( ( pev->health < -40 && iGib != GIB_NEVER ) || iGib == GIB_ALWAYS ) - { - pev->solid = SOLID_NOT; - GibMonster(); // This clears pev->model - pev->effects |= EF_NODRAW; - return; - } - - DeathSound(); - - pev->angles.x = 0; - pev->angles.z = 0; - - SetThink(&CBasePlayer::PlayerDeathThink); - pev->nextthink = gpGlobals->time + 0.1; -} - - -// Set the activity based on an event or current state -void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) -{ - int animDesired; - float speed; - char szAnim[64]; - - speed = pev->velocity.Length2D(); - - if (pev->flags & FL_FROZEN) - { - speed = 0; - playerAnim = PLAYER_IDLE; - } - - switch (playerAnim) - { - case PLAYER_JUMP: - m_IdealActivity = ACT_HOP; - break; - - case PLAYER_SUPERJUMP: - m_IdealActivity = ACT_LEAP; - break; - - case PLAYER_DIE: - m_IdealActivity = ACT_DIESIMPLE; - m_IdealActivity = GetDeathActivity( ); - break; - - case PLAYER_ATTACK1: - switch( m_Activity ) - { - case ACT_HOVER: - case ACT_SWIM: - case ACT_HOP: - case ACT_LEAP: - case ACT_DIESIMPLE: - m_IdealActivity = m_Activity; - break; - default: - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - break; - case PLAYER_IDLE: - case PLAYER_WALK: - if ( !FBitSet( pev->flags, FL_ONGROUND ) && (m_Activity == ACT_HOP || m_Activity == ACT_LEAP) ) // Still jumping - { - m_IdealActivity = m_Activity; - } - else if ( pev->waterlevel > 1 ) - { - if ( speed == 0 ) - m_IdealActivity = ACT_HOVER; - else - m_IdealActivity = ACT_SWIM; - } - else - { - m_IdealActivity = ACT_WALK; - } - break; - } - - switch (m_IdealActivity) - { - case ACT_HOVER: - case ACT_LEAP: - case ACT_SWIM: - case ACT_HOP: - case ACT_DIESIMPLE: - default: - if ( m_Activity == m_IdealActivity) - return; - m_Activity = m_IdealActivity; - - animDesired = LookupActivity( m_Activity ); - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - pev->gaitsequence = 0; - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); - return; - - case ACT_RANGE_ATTACK1: - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching - strcpy( szAnim, "crouch_shoot_" ); - else - strcpy( szAnim, "ref_shoot_" ); - strcat( szAnim, m_szAnimExtention ); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - animDesired = 0; - - if ( pev->sequence != animDesired || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - if (!m_fSequenceLoops) - { - pev->effects |= EF_NOINTERP; - } - - m_Activity = m_IdealActivity; - - pev->sequence = animDesired; - ResetSequenceInfo( ); - break; - - case ACT_WALK: - if (m_Activity != ACT_RANGE_ATTACK1 || m_fSequenceFinished) - { - if ( FBitSet( pev->flags, FL_DUCKING ) ) // crouching - strcpy( szAnim, "crouch_aim_" ); - else - strcpy( szAnim, "ref_aim_" ); - strcat( szAnim, m_szAnimExtention ); - animDesired = LookupSequence( szAnim ); - if (animDesired == -1) - animDesired = 0; - m_Activity = ACT_WALK; - } - else - { - animDesired = pev->sequence; - } - } - - if ( FBitSet( pev->flags, FL_DUCKING ) ) - { - if ( speed == 0) - { - pev->gaitsequence = LookupActivity( ACT_CROUCHIDLE ); - // pev->gaitsequence = LookupActivity( ACT_CROUCH ); - } - else - { - pev->gaitsequence = LookupActivity( ACT_CROUCH ); - } - } - else if ( speed > 220 ) - { - pev->gaitsequence = LookupActivity( ACT_RUN ); - } - else if (speed > 0) - { - pev->gaitsequence = LookupActivity( ACT_WALK ); - } - else - { - // pev->gaitsequence = LookupActivity( ACT_WALK ); - pev->gaitsequence = LookupSequence( "deep_idle" ); - } - - - // Already using the desired animation? - if (pev->sequence == animDesired) - return; - - //ALERT( at_console, "Set animation to %d\n", animDesired ); - // Reset to first frame of desired animation - pev->sequence = animDesired; - pev->frame = 0; - ResetSequenceInfo( ); -} - -/* -=========== -TabulateAmmo -This function is used to find and store -all the ammo we have into the ammo vars. -============ -*/ -void CBasePlayer::TabulateAmmo() -{ - ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) ); - ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) ); - ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) ); - ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) ); - ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) ); - ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) ); - ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) ); - ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) ); -} - - -/* -=========== -WaterMove -============ -*/ -#define AIRTIME 12 // lung full of air lasts this many seconds - -void CBasePlayer::WaterMove() -{ - int air; - - if (pev->movetype == MOVETYPE_NOCLIP) - return; - - if (pev->health < 0) - return; - - // waterlevel 0 - not in water - // waterlevel 1 - feet in water - // waterlevel 2 - waist in water - // waterlevel 3 - head in water - - if (pev->waterlevel != 3) - { - // not underwater - - // play 'up for air' sound - if (pev->air_finished < gpGlobals->time) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade1.wav", 1, ATTN_NORM); - else if (pev->air_finished < gpGlobals->time + 9) - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_wade2.wav", 1, ATTN_NORM); - - pev->air_finished = gpGlobals->time + AIRTIME; - pev->dmg = 2; - - // if we took drowning damage, give it back slowly - if (m_idrowndmg > m_idrownrestored) - { - // set drowning damage bit. hack - dmg_drownrecover actually - // makes the time based damage code 'give back' health over time. - // make sure counter is cleared so we start count correctly. - - // NOTE: this actually causes the count to continue restarting - // until all drowning damage is healed. - - m_bitsDamageType |= DMG_DROWNRECOVER; - m_bitsDamageType &= ~DMG_DROWN; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - } - - } - else - { // fully under water - // stop restoring damage while underwater - m_bitsDamageType &= ~DMG_DROWNRECOVER; - m_rgbTimeBasedDamage[itbd_DrownRecover] = 0; - - if (pev->air_finished < gpGlobals->time) // drown! - { - if (pev->pain_finished < gpGlobals->time) - { - // take drowning damage - pev->dmg += 1; - if (pev->dmg > 5) - pev->dmg = 5; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), pev->dmg, DMG_DROWN); - pev->pain_finished = gpGlobals->time + 1; - - // track drowning damage, give it back when - // player finally takes a breath - - m_idrowndmg += static_cast(pev->dmg); - } - } - else - { - m_bitsDamageType &= ~DMG_DROWN; - } - } - - if (!pev->waterlevel) - { - if (FBitSet(pev->flags, FL_INWATER)) - { - ClearBits(pev->flags, FL_INWATER); - } - return; - } - - // make bubbles - - air = (int)(pev->air_finished - gpGlobals->time); - if (!RANDOM_LONG(0,0x1f) && RANDOM_LONG(0,AIRTIME-1) >= air) - { - switch (RANDOM_LONG(0,3)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim1.wav", 0.8, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim2.wav", 0.8, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim3.wav", 0.8, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_swim4.wav", 0.8, ATTN_NORM); break; - } - } - - if (pev->watertype == CONTENT_LAVA) // do damage - { - if (pev->dmgtime < gpGlobals->time) - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 10 * pev->waterlevel, DMG_BURN); - } - else if (pev->watertype == CONTENT_SLIME) // do damage - { - pev->dmgtime = gpGlobals->time + 1; - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), 4 * pev->waterlevel, DMG_ACID); - } - - if (!FBitSet(pev->flags, FL_INWATER)) - { - SetBits(pev->flags, FL_INWATER); - pev->dmgtime = 0; - } -} - - -// TRUE if the player is attached to a ladder -BOOL CBasePlayer::IsOnLadder( void ) -{ - return ( pev->movetype == MOVETYPE_FLY ); -} - -void CBasePlayer::PlayerDeathThink(void) -{ - float flForward; - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - flForward = pev->velocity.Length() - 20; - if (flForward <= 0) - pev->velocity = g_vecZero; - else - pev->velocity = flForward * pev->velocity.Normalize(); - } - - if ( HasWeapons() ) - { - // we drop the guns here because weapons that have an area effect and can kill their user - // will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the - // player class sometimes is freed. It's safer to manipulate the weapons once we know - // we aren't calling into any of their code anymore through the player pointer. - PackDeadPlayerItems(); - } - - - if (pev->modelindex && (!m_fSequenceFinished) && (pev->deadflag == DEAD_DYING)) - { - StudioFrameAdvance( ); - - m_iRespawnFrames++; // Note, these aren't necessarily real "frames", so behavior is dependent on # of client movement commands - if ( m_iRespawnFrames < 120 ) // Animations should be no longer than this - return; - } - - // once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore - // this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn - if ( pev->movetype != MOVETYPE_NONE && FBitSet(pev->flags, FL_ONGROUND) ) - pev->movetype = MOVETYPE_NONE; - - if (pev->deadflag == DEAD_DYING) - pev->deadflag = DEAD_DEAD; - - StopAnimation(); - - pev->effects |= EF_NOINTERP; - pev->framerate = 0.0; - - BOOL fAnyButtonDown = (pev->button & ~IN_SCORE ); - - // wait for all buttons released - if (pev->deadflag == DEAD_DEAD) - { - if (fAnyButtonDown) - return; - - if ( g_pGameRules->FPlayerCanRespawn( this ) ) - { - m_fDeadTime = gpGlobals->time; - pev->deadflag = DEAD_RESPAWNABLE; - } - - return; - } - -// if the player has been dead for one second longer than allowed by forcerespawn, -// forcerespawn isn't on. Send the player off to an intermission camera until they -// choose to respawn. - if ( g_pGameRules->IsMultiplayer() && ( gpGlobals->time > (m_fDeadTime + 6) ) && !(m_afPhysicsFlags & PFLAG_OBSERVER) ) - { - // go to dead camera. - StartDeathCam(); - } - - if ( pev->iuser1 ) // player is in spectator mode - return; - -// wait for any button down, or mp_forcerespawn is set and the respawn time is up - if (!fAnyButtonDown - && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && (gpGlobals->time > (m_fDeadTime + 5))) ) - return; - - pev->button = 0; - m_iRespawnFrames = 0; - - //ALERT(at_console, "Respawn\n"); - - respawn(pev, !(m_afPhysicsFlags & PFLAG_OBSERVER) );// don't copy a corpse if we're in deathcam. - pev->nextthink = -1; -} - -//========================================================= -// StartDeathCam - find an intermission spot and send the -// player off into observer mode -//========================================================= -void CBasePlayer::StartDeathCam( void ) -{ - edict_t *pSpot, *pNewSpot; - int iRand; - - if ( pev->view_ofs == g_vecZero ) - { - // don't accept subsequent attempts to StartDeathCam() - return; - } - - pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission"); - - if ( !FNullEnt( pSpot ) ) - { - // at least one intermission spot in the world. - iRand = RANDOM_LONG( 0, 3 ); - - while ( iRand > 0 ) - { - pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission"); - - if ( pNewSpot ) - { - pSpot = pNewSpot; - } - - iRand--; - } - - CopyToBodyQue( pev ); - - UTIL_SetOrigin( pev, pSpot->v.origin ); - pev->angles = pev->v_angle = pSpot->v.v_angle; - } - else - { - // no intermission spot. Push them up in the air, looking down at their corpse - TraceResult tr; - CopyToBodyQue( pev ); - UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - - UTIL_SetOrigin( pev, tr.vecEndPos ); - pev->angles = pev->v_angle = UTIL_VecToAngles( tr.vecEndPos - pev->origin ); - } - - // start death cam - - m_afPhysicsFlags |= PFLAG_OBSERVER; - pev->view_ofs = g_vecZero; - pev->fixangle = TRUE; - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - pev->movetype = MOVETYPE_NONE; - pev->modelindex = 0; -} - -void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) -{ - // clear any clientside entities attached to this player - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); - WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); - WRITE_BYTE( (BYTE)entindex() ); - MESSAGE_END(); - - // Holster weapon immediately, to allow it to cleanup - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - if ( m_pTank != 0 ) - { - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - - // clear out the suit message cache so we don't keep chattering - SetSuitUpdate(NULL, FALSE, 0); - - // Tell Ammo Hud that the player is dead - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(0XFF); - WRITE_BYTE(0xFF); - MESSAGE_END(); - - // reset FOV - m_iFOV = m_iClientFOV = 0; - pev->fov = m_iFOV; - MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); - WRITE_BYTE(0); - MESSAGE_END(); - - // Setup flags - m_iHideHUD = (HIDEHUD_HEALTH | HIDEHUD_WEAPONS); - m_afPhysicsFlags |= PFLAG_OBSERVER; - pev->effects = EF_NODRAW; - pev->view_ofs = g_vecZero; - pev->angles = pev->v_angle = vecViewAngle; - pev->fixangle = TRUE; - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - pev->movetype = MOVETYPE_NONE; - ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); - ClearBits( pev->flags, FL_DUCKING ); - pev->deadflag = DEAD_RESPAWNABLE; - pev->health = 1; - - // Clear out the status bar - m_fInitHUD = TRUE; - - pev->team = 0; - MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); - WRITE_BYTE( ENTINDEX(edict()) ); - WRITE_STRING( "" ); - MESSAGE_END(); - - // Remove all the player's stuff - RemoveAllItems( FALSE ); - - // Move them to the new position - UTIL_SetOrigin( pev, vecPosition ); - - // Find a player to watch - m_flNextObserverInput = 0; - Observer_SetMode( m_iObserverLastMode ); -} - -// -// PlayerUse - handles USE keypress -// -#define PLAYER_SEARCH_RADIUS (float)64 - -void CBasePlayer::PlayerUse ( void ) -{ - if ( IsObserver() ) - return; - - // Was use pressed or released? - if ( ! ((pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE) ) - return; - - // Hit Use on a train? - if ( m_afButtonPressed & IN_USE ) - { - if ( m_pTank != 0 ) - { - // Stop controlling the tank - // TODO: Send HUD Update - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - return; - } - else - { - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - else - { // Start controlling the train! - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - - if ( pTrain && !(pev->button & IN_JUMP) && FBitSet(pev->flags, FL_ONGROUND) && (pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) && pTrain->OnControls(pev) ) - { - m_afPhysicsFlags |= PFLAG_ONTRAIN; - m_iTrain = TrainSpeed(static_cast(pTrain->pev->speed), pTrain->pev->impulse); - m_iTrain |= TRAIN_NEW; - EMIT_SOUND( ENT(pev), CHAN_ITEM, "plats/train_use1.wav", 0.8, ATTN_NORM); - return; - } - } - } - } - - CBaseEntity *pObject = NULL; - CBaseEntity *pClosest = NULL; - Vector vecLOS; - float flMaxDot = VIEW_FIELD_NARROW; - float flDot; - - UTIL_MakeVectors ( pev->v_angle );// so we know which way we are facing - - while ((pObject = UTIL_FindEntityInSphere( pObject, pev->origin, PLAYER_SEARCH_RADIUS )) != NULL) - { - - if (pObject->ObjectCaps() & (FCAP_IMPULSE_USE | FCAP_CONTINUOUS_USE | FCAP_ONOFF_USE)) - { - // !!!PERFORMANCE- should this check be done on a per case basis AFTER we've determined that - // this object is actually usable? This dot is being done for every object within PLAYER_SEARCH_RADIUS - // when player hits the use key. How many objects can be in that area, anyway? (sjb) - vecLOS = (VecBModelOrigin( pObject->pev ) - (pev->origin + pev->view_ofs)); - - // This essentially moves the origin of the target to the corner nearest the player to test to see - // if it's "hull" is in the view cone - vecLOS = UTIL_ClampVectorToBox( vecLOS, pObject->pev->size * 0.5 ); - - flDot = DotProduct (vecLOS , gpGlobals->v_forward); - if (flDot > flMaxDot ) - {// only if the item is in front of the user - pClosest = pObject; - flMaxDot = flDot; -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } -// ALERT( at_console, "%s : %f\n", STRING( pObject->pev->classname ), flDot ); - } - } - pObject = pClosest; - - // Found an object - if (pObject ) - { - //!!!UNDONE: traceline here to prevent USEing buttons through walls - int caps = pObject->ObjectCaps(); - - if ( m_afButtonPressed & IN_USE ) - EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_select.wav", 0.4, ATTN_NORM); - - if ( ( (pev->button & IN_USE) && (caps & FCAP_CONTINUOUS_USE) ) || - ( (m_afButtonPressed & IN_USE) && (caps & (FCAP_IMPULSE_USE|FCAP_ONOFF_USE)) ) ) - { - if ( caps & FCAP_CONTINUOUS_USE ) - m_afPhysicsFlags |= PFLAG_USING; - - pObject->Use( this, this, USE_SET, 1 ); - } - // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away - else if ( (m_afButtonReleased & IN_USE) && (pObject->ObjectCaps() & FCAP_ONOFF_USE) ) // BUGBUG This is an "off" use - { - pObject->Use( this, this, USE_SET, 0 ); - } - } - else - { - if ( m_afButtonPressed & IN_USE ) - EMIT_SOUND( ENT(pev), CHAN_ITEM, "common/wpn_denyselect.wav", 0.4, ATTN_NORM); - } -} - - - -void CBasePlayer::Jump() -{ - Vector vecWallCheckDir;// direction we're tracing a line to find a wall when walljumping - Vector vecAdjustedVelocity; - Vector vecSpot; - TraceResult tr; - - if (FBitSet(pev->flags, FL_WATERJUMP)) - return; - - if (pev->waterlevel >= 2) - { - return; - } - - // jump velocity is sqrt( height * gravity * 2) - - // If this isn't the first frame pressing the jump button, break out. - if ( !FBitSet( m_afButtonPressed, IN_JUMP ) ) - return; // don't pogo stick - - if ( !(pev->flags & FL_ONGROUND) || !pev->groundentity ) - { - return; - } - -// many features in this function use v_forward, so makevectors now. - UTIL_MakeVectors (pev->angles); - - // ClearBits(pev->flags, FL_ONGROUND); // don't stairwalk - - SetAnimation( PLAYER_JUMP ); - - if ( m_fLongJump && - (pev->button & IN_DUCK) && - ( pev->flDuckTime > 0 ) && - pev->velocity.Length() > 50 ) - { - SetAnimation( PLAYER_SUPERJUMP ); - } - - // If you're standing on a conveyor, add it's velocity to yours (for momentum) - entvars_t *pevGround = VARS(pev->groundentity); - if ( pevGround && (pevGround->flags & FL_CONVEYOR) ) - { - pev->velocity = pev->velocity + pev->basevelocity; - } -} - - - -// This is a glorious hack to find free space when you've crouched into some solid space -// Our crouching collisions do not work correctly for some reason and this is easier -// than fixing the problem :( -void FixPlayerCrouchStuck( edict_t *pPlayer ) -{ - TraceResult trace; - - // Move up as many as 18 pixels if the player is stuck. - for ( int i = 0; i < 18; i++ ) - { - UTIL_TraceHull( pPlayer->v.origin, pPlayer->v.origin, dont_ignore_monsters, head_hull, pPlayer, &trace ); - if ( trace.fStartSolid ) - pPlayer->v.origin.z ++; - else - break; - } -} - -void CBasePlayer::Duck( ) -{ - if (pev->button & IN_DUCK) - { - if ( m_IdealActivity != ACT_LEAP ) - { - SetAnimation( PLAYER_WALK ); - } - } -} - -// -// ID's player as such. -// -int CBasePlayer::Classify ( void ) -{ - return CLASS_PLAYER; -} - - -void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) -{ - // Positive score always adds - if ( score < 0 ) - { - if ( !bAllowNegativeScore ) - { - if ( pev->frags < 0 ) // Can't go more negative - return; - - if ( -score > pev->frags ) // Will this go negative? - { - score = static_cast(-pev->frags); // Sum will be 0 - } - } - } - - pev->frags += score; - - MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( ENTINDEX(edict()) ); - WRITE_SHORT( static_cast(pev->frags) ); - WRITE_SHORT( m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( g_pGameRules->GetTeamIndex( m_szTeamName ) + 1 ); - MESSAGE_END(); -} - - -void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) -{ - int index = entindex(); - - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( pPlayer && i != index ) - { - if ( g_pGameRules->PlayerRelationship( this, pPlayer ) == GR_TEAMMATE ) - { - pPlayer->AddPoints( score, bAllowNegativeScore ); - } - } - } -} - -//Player ID -void CBasePlayer::InitStatusBar() -{ - m_flStatusBarDisappearDelay = 0; - m_SbarString1[0] = m_SbarString0[0] = 0; -} - -void CBasePlayer::UpdateStatusBar() -{ - int newSBarState[ SBAR_END ]; - char sbuf0[ SBAR_STRING_SIZE ]; - char sbuf1[ SBAR_STRING_SIZE ]; - - memset( newSBarState, 0, sizeof(newSBarState) ); - strcpy( sbuf0, m_SbarString0 ); - strcpy( sbuf1, m_SbarString1 ); - - // Find an ID Target - TraceResult tr; - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - Vector vecSrc = EyePosition(); - Vector vecEnd = vecSrc + (gpGlobals->v_forward * MAX_ID_RANGE); - UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, edict(), &tr); - - if (tr.flFraction != 1.0) - { - if ( !FNullEnt( tr.pHit ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - - if (pEntity->Classify() == CLASS_PLAYER ) - { - newSBarState[ SBAR_ID_TARGETNAME ] = ENTINDEX( pEntity->edict() ); - strcpy( sbuf1, "1 %p1\n2 Health: %i2%%\n3 Armor: %i3%%" ); - - // allies and medics get to see the targets health - if ( g_pGameRules->PlayerRelationship( this, pEntity ) == GR_TEAMMATE ) - { - newSBarState[ SBAR_ID_TARGETHEALTH ] = static_cast(100 * (pEntity->pev->health / pEntity->pev->max_health)); - newSBarState[ SBAR_ID_TARGETARMOR ] = static_cast(pEntity->pev->armorvalue); //No need to get it % based since 100 it's the max. - } - - m_flStatusBarDisappearDelay = gpGlobals->time + 1.0; - } - } - else if ( m_flStatusBarDisappearDelay > gpGlobals->time ) - { - // hold the values for a short amount of time after viewing the object - newSBarState[ SBAR_ID_TARGETNAME ] = m_izSBarState[ SBAR_ID_TARGETNAME ]; - newSBarState[ SBAR_ID_TARGETHEALTH ] = m_izSBarState[ SBAR_ID_TARGETHEALTH ]; - newSBarState[ SBAR_ID_TARGETARMOR ] = m_izSBarState[ SBAR_ID_TARGETARMOR ]; - } - } - - BOOL bForceResend = FALSE; - - if ( strcmp( sbuf0, m_SbarString0 ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev ); - WRITE_BYTE( 0 ); - WRITE_STRING( sbuf0 ); - MESSAGE_END(); - - strcpy( m_SbarString0, sbuf0 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - if ( strcmp( sbuf1, m_SbarString1 ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgStatusText, NULL, pev ); - WRITE_BYTE( 1 ); - WRITE_STRING( sbuf1 ); - MESSAGE_END(); - - strcpy( m_SbarString1, sbuf1 ); - - // make sure everything's resent - bForceResend = TRUE; - } - - // Check values and send if they don't match - for (int i = 1; i < SBAR_END; i++) - { - if ( newSBarState[i] != m_izSBarState[i] || bForceResend ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgStatusValue, NULL, pev ); - WRITE_BYTE( i ); - WRITE_SHORT( newSBarState[i] ); - MESSAGE_END(); - - m_izSBarState[i] = newSBarState[i]; - } - } -} - - - - - - - - - -#define CLIMB_SHAKE_FREQUENCY 22 // how many frames in between screen shakes when climbing -#define MAX_CLIMB_SPEED 200 // fastest vertical climbing speed possible -#define CLIMB_SPEED_DEC 15 // climbing deceleration rate -#define CLIMB_PUNCH_X -7 // how far to 'punch' client X axis when climbing -#define CLIMB_PUNCH_Z 7 // how far to 'punch' client Z axis when climbing - -void CBasePlayer::PreThink(void) -{ - int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame - - // Debounced button codes for pressed/released - // UNDONE: Do we need auto-repeat? - m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" - m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released" - - g_pGameRules->PlayerThink( this ); - - if ( g_fGameOver ) - return; // intermission or finale - - UTIL_MakeVectors(pev->v_angle); // is this still used? - - ItemPreFrame( ); - WaterMove(); - - if ( g_pGameRules && g_pGameRules->FAllowFlashlight() ) - m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; - else - m_iHideHUD |= HIDEHUD_FLASHLIGHT; - - - // JOHN: checks if new client data (for HUD and view control) needs to be sent to the client - UpdateClientData(); - - CheckTimeBasedDamage(); - - CheckSuitUpdate(); - - // Observer Button Handling - if ( IsObserver() ) - { - Observer_HandleButtons(); - Observer_CheckTarget(); - Observer_CheckProperties(); - pev->impulse = 0; - return; - } - - if (pev->deadflag >= DEAD_DYING) - { - PlayerDeathThink(); - return; - } - - // So the correct flags get sent to client asap. - // - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - pev->flags |= FL_ONTRAIN; - else - pev->flags &= ~FL_ONTRAIN; - - // Train speed control - if ( m_afPhysicsFlags & PFLAG_ONTRAIN ) - { - CBaseEntity *pTrain = CBaseEntity::Instance( pev->groundentity ); - float vel; - - if ( !pTrain ) - { - TraceResult trainTrace; - // Maybe this is on the other side of a level transition - UTIL_TraceLine( pev->origin, pev->origin + Vector(0,0,-38), ignore_monsters, ENT(pev), &trainTrace ); - - // HACKHACK - Just look for the func_tracktrain classname - if ( trainTrace.flFraction != 1.0 && trainTrace.pHit ) - pTrain = CBaseEntity::Instance( trainTrace.pHit ); - - - if ( !pTrain || !(pTrain->ObjectCaps() & FCAP_DIRECTIONAL_USE) || !pTrain->OnControls(pev) ) - { - //ALERT( at_error, "In train mode with no train!\n" ); - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - } - else if ( !FBitSet( pev->flags, FL_ONGROUND ) || FBitSet( pTrain->pev->spawnflags, SF_TRACKTRAIN_NOCONTROL ) || (pev->button & (IN_MOVELEFT|IN_MOVERIGHT) ) ) - { - // Turn off the train if you jump, strafe, or the train controls go dead - m_afPhysicsFlags &= ~PFLAG_ONTRAIN; - m_iTrain = TRAIN_NEW|TRAIN_OFF; - return; - } - - pev->velocity = g_vecZero; - vel = 0; - if ( m_afButtonPressed & IN_FORWARD ) - { - vel = 1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - else if ( m_afButtonPressed & IN_BACK ) - { - vel = -1; - pTrain->Use( this, this, USE_SET, (float)vel ); - } - - if (vel) - { - m_iTrain = TrainSpeed(static_cast(pTrain->pev->speed), pTrain->pev->impulse); - m_iTrain |= TRAIN_ACTIVE|TRAIN_NEW; - } - - } else if (m_iTrain & TRAIN_ACTIVE) - m_iTrain = TRAIN_NEW; // turn off train - - if (pev->button & IN_JUMP) - { - // If on a ladder, jump off the ladder - // else Jump - Jump(); - } - - - // If trying to duck, already ducked, or in the process of ducking - if ((pev->button & IN_DUCK) || FBitSet(pev->flags,FL_DUCKING) || (m_afPhysicsFlags & PFLAG_DUCKING) ) - Duck(); - - if ( !FBitSet ( pev->flags, FL_ONGROUND ) ) - { - m_flFallVelocity = -pev->velocity.z; - } - - // StudioFrameAdvance( );//!!!HACKHACK!!! Can't be hit by traceline when not animating? - - // Clear out ladder pointer - m_hEnemy = NULL; - - if ( m_afPhysicsFlags & PFLAG_ONBARNACLE ) - { - pev->velocity = g_vecZero; - } -} -/* Time based Damage works as follows: - 1) There are several types of timebased damage: - - #define DMG_PARALYZE (1 << 14) // slows affected creature down - #define DMG_NERVEGAS (1 << 15) // nerve toxins, very bad - #define DMG_POISON (1 << 16) // blood poisioning - #define DMG_RADIATION (1 << 17) // radiation exposure - #define DMG_DROWNRECOVER (1 << 18) // drown recovery - #define DMG_ACID (1 << 19) // toxic chemicals or acid burns - #define DMG_SLOWBURN (1 << 20) // in an oven - #define DMG_SLOWFREEZE (1 << 21) // in a subzero freezer - - 2) A new hit inflicting tbd restarts the tbd counter - each monster has an 8bit counter, - per damage type. The counter is decremented every second, so the maximum time - an effect will last is 255/60 = 4.25 minutes. Of course, staying within the radius - of a damaging effect like fire, nervegas, radiation will continually reset the counter to max. - - 3) Every second that a tbd counter is running, the player takes damage. The damage - is determined by the type of tdb. - Paralyze - 1/2 movement rate, 30 second duration. - Nervegas - 5 points per second, 16 second duration = 80 points max dose. - Poison - 2 points per second, 25 second duration = 50 points max dose. - Radiation - 1 point per second, 50 second duration = 50 points max dose. - Drown - 5 points per second, 2 second duration. - Acid/Chemical - 5 points per second, 10 second duration = 50 points max. - Burn - 10 points per second, 2 second duration. - Freeze - 3 points per second, 10 second duration = 30 points max. - - 4) Certain actions or countermeasures counteract the damaging effects of tbds: - - Armor/Heater/Cooler - Chemical(acid),burn, freeze all do damage to armor power, then to body - - recharged by suit recharger - Air In Lungs - drowning damage is done to air in lungs first, then to body - - recharged by poking head out of water - - 10 seconds if swiming fast - Air In SCUBA - drowning damage is done to air in tanks first, then to body - - 2 minutes in tanks. Need new tank once empty. - Radiation Syringe - Each syringe full provides protection vs one radiation dosage - Antitoxin Syringe - Each syringe full provides protection vs one poisoning (nervegas or poison). - Health kit - Immediate stop to acid/chemical, fire or freeze damage. - Radiation Shower - Immediate stop to radiation damage, acid/chemical or fire damage. - - -*/ - -// If player is taking time based damage, continue doing damage to player - -// this simulates the effect of being poisoned, gassed, dosed with radiation etc - -// anything that continues to do damage even after the initial contact stops. -// Update all time based damage counters, and shut off any that are done. - -// The m_bitsDamageType bit MUST be set if any damage is to be taken. -// This routine will detect the initial on value of the m_bitsDamageType -// and init the appropriate counter. Only processes damage every second. - -//#define PARALYZE_DURATION 30 // number of 2 second intervals to take damage -//#define PARALYZE_DAMAGE 0.0 // damage to take each 2 second interval - -//#define NERVEGAS_DURATION 16 -//#define NERVEGAS_DAMAGE 5.0 - -//#define POISON_DURATION 25 -//#define POISON_DAMAGE 2.0 - -//#define RADIATION_DURATION 50 -//#define RADIATION_DAMAGE 1.0 - -//#define ACID_DURATION 10 -//#define ACID_DAMAGE 5.0 - -//#define SLOWBURN_DURATION 2 -//#define SLOWBURN_DAMAGE 1.0 - -//#define SLOWFREEZE_DURATION 1.0 -//#define SLOWFREEZE_DAMAGE 3.0 - -/* */ - - -void CBasePlayer::CheckTimeBasedDamage() -{ - int i; - BYTE bDuration = 0; - - if (!(m_bitsDamageType & DMG_TIMEBASED)) - return; - - // only check for time based damage approx. every 2 seconds - if (abs(static_cast(gpGlobals->time - m_tbdPrev)) < 2.0) - return; - - m_tbdPrev = gpGlobals->time; - - for (i = 0; i < CDMG_TIMEBASED; i++) - { - // make sure bit is set for damage type - if (m_bitsDamageType & (DMG_PARALYZE << i)) - { - switch (i) - { - case itbd_Paralyze: - // UNDONE - flag movement as half-speed - bDuration = PARALYZE_DURATION; - break; - case itbd_NerveGas: -// TakeDamage(pev, pev, NERVEGAS_DAMAGE, DMG_GENERIC); - bDuration = NERVEGAS_DURATION; - break; - case itbd_Poison: - TakeDamage(pev, pev, POISON_DAMAGE, DMG_GENERIC); - bDuration = POISON_DURATION; - break; - case itbd_Radiation: -// TakeDamage(pev, pev, RADIATION_DAMAGE, DMG_GENERIC); - bDuration = RADIATION_DURATION; - break; - case itbd_DrownRecover: - // NOTE: this hack is actually used to RESTORE health - // after the player has been drowning and finally takes a breath - if (m_idrowndmg > m_idrownrestored) - { - int idif = min(m_idrowndmg - m_idrownrestored, 10); - - TakeHealth(idif, DMG_GENERIC); - m_idrownrestored += idif; - } - bDuration = 4; // get up to 5*10 = 50 points back - break; - case itbd_Acid: -// TakeDamage(pev, pev, ACID_DAMAGE, DMG_GENERIC); - bDuration = ACID_DURATION; - break; - case itbd_SlowBurn: -// TakeDamage(pev, pev, SLOWBURN_DAMAGE, DMG_GENERIC); - bDuration = SLOWBURN_DURATION; - break; - case itbd_SlowFreeze: -// TakeDamage(pev, pev, SLOWFREEZE_DAMAGE, DMG_GENERIC); - bDuration = SLOWFREEZE_DURATION; - break; - default: - bDuration = 0; - } - - if (m_rgbTimeBasedDamage[i]) - { - // use up an antitoxin on poison or nervegas after a few seconds of damage - if (((i == itbd_NerveGas) && (m_rgbTimeBasedDamage[i] < NERVEGAS_DURATION)) || - ((i == itbd_Poison) && (m_rgbTimeBasedDamage[i] < POISON_DURATION))) - { - if (m_rgItems[ITEM_ANTIDOTE]) - { - m_rgbTimeBasedDamage[i] = 0; - m_rgItems[ITEM_ANTIDOTE]--; - SetSuitUpdate("!HEV_HEAL4", FALSE, SUIT_REPEAT_OK); - } - } - - - // decrement damage duration, detect when done. - if (!m_rgbTimeBasedDamage[i] || --m_rgbTimeBasedDamage[i] == 0) - { - m_rgbTimeBasedDamage[i] = 0; - // if we're done, clear damage bits - m_bitsDamageType &= ~(DMG_PARALYZE << i); - } - } - else - // first time taking this damage type - init damage duration - m_rgbTimeBasedDamage[i] = bDuration; - } - } -} - -/* -THE POWER SUIT - -The Suit provides 3 main functions: Protection, Notification and Augmentation. -Some functions are automatic, some require power. -The player gets the suit shortly after getting off the train in C1A0 and it stays -with him for the entire game. - -Protection - - Heat/Cold - When the player enters a hot/cold area, the heating/cooling indicator on the suit - will come on and the battery will drain while the player stays in the area. - After the battery is dead, the player starts to take damage. - This feature is built into the suit and is automatically engaged. - Radiation Syringe - This will cause the player to be immune from the effects of radiation for N seconds. Single use item. - Anti-Toxin Syringe - This will cure the player from being poisoned. Single use item. - Health - Small (1st aid kits, food, etc.) - Large (boxes on walls) - Armor - The armor works using energy to create a protective field that deflects a - percentage of damage projectile and explosive attacks. After the armor has been deployed, - it will attempt to recharge itself to full capacity with the energy reserves from the battery. - It takes the armor N seconds to fully charge. - -Notification (via the HUD) - -x Health -x Ammo -x Automatic Health Care - Notifies the player when automatic healing has been engaged. -x Geiger counter - Classic Geiger counter sound and status bar at top of HUD - alerts player to dangerous levels of radiation. This is not visible when radiation levels are normal. -x Poison - Armor - Displays the current level of armor. - -Augmentation - - Reanimation (w/adrenaline) - Causes the player to come back to life after he has been dead for 3 seconds. - Will not work if player was gibbed. Single use. - Long Jump - Used by hitting the ??? key(s). Caused the player to further than normal. - SCUBA - Used automatically after picked up and after player enters the water. - Works for N seconds. Single use. - -Things powered by the battery - - Armor - Uses N watts for every M units of damage. - Heat/Cool - Uses N watts for every second in hot/cold area. - Long Jump - Uses N watts for every jump. - Alien Cloak - Uses N watts for each use. Each use lasts M seconds. - Alien Shield - Augments armor. Reduces Armor drain by one half - -*/ - -// if in range of radiation source, ping geiger counter - -#define GEIGERDELAY 0.25 - -void CBasePlayer :: UpdateGeigerCounter( void ) -{ - BYTE range; - - // delay per update ie: don't flood net with these msgs - if (gpGlobals->time < m_flgeigerDelay) - return; - - m_flgeigerDelay = gpGlobals->time + GEIGERDELAY; - - // send range to radition source to client - - range = (BYTE) (m_flgeigerRange / 4); - - if (range != m_igeigerRangePrev) - { - m_igeigerRangePrev = range; - - MESSAGE_BEGIN( MSG_ONE, gmsgGeigerRange, NULL, pev ); - WRITE_BYTE( range ); - MESSAGE_END(); - } - - // reset counter and semaphore - if (!RANDOM_LONG(0,3)) - m_flgeigerRange = 1000; - -} - -/* -================ -CheckSuitUpdate - -Play suit update if it's time -================ -*/ - -#define SUITUPDATETIME 3.5 -#define SUITFIRSTUPDATETIME 0.1 - -void CBasePlayer::CheckSuitUpdate() -{ - int i; - int isentence = 0; - int isearch = m_iSuitPlayNext; - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // don't bother updating HEV voice in multiplayer. - return; - } - - if ( gpGlobals->time >= m_flSuitUpdate && m_flSuitUpdate > 0) - { - // play a sentence off of the end of the queue - for (i = 0; i < CSUITPLAYLIST; i++) - { - if ((isentence = m_rgSuitPlayList[isearch])) - break; - - if (++isearch == CSUITPLAYLIST) - isearch = 0; - } - - if (isentence) - { - m_rgSuitPlayList[isearch] = 0; - if (isentence > 0) - { - // play sentence number - - char sentence[CBSENTENCENAME_MAX+1]; - strcpy(sentence, "!"); - strcat(sentence, gszallsentencenames[isentence]); - EMIT_SOUND_SUIT(ENT(pev), sentence); - } - else - { - // play sentence group - EMIT_GROUPID_SUIT(ENT(pev), -isentence); - } - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - else - // queue is empty, don't check - m_flSuitUpdate = 0; - } -} - -// add sentence to suit playlist queue. if fgroup is true, then -// name is a sentence group (HEV_AA), otherwise name is a specific -// sentence name ie: !HEV_AA0. If iNoRepeat is specified in -// seconds, then we won't repeat playback of this word or sentence -// for at least that number of seconds. - -void CBasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeatTime) -{ - int i; - int isentence; - int iempty = -1; - - - // Ignore suit updates if no suit - if ( !(pev->weapons & (1<IsMultiplayer() ) - { - // due to static channel design, etc. We don't play HEV sounds in multiplayer right now. - return; - } - - // if name == NULL, then clear out the queue - - if (!name) - { - for (i = 0; i < CSUITPLAYLIST; i++) - m_rgSuitPlayList[i] = 0; - return; - } - // get sentence or group number - if (!fgroup) - { - isentence = SENTENCEG_Lookup(name, NULL); - if (isentence < 0) - return; - } - else - // mark group number as negative - isentence = -SENTENCEG_GetIndex(name); - - // check norepeat list - this list lets us cancel - // the playback of words or sentences that have already - // been played within a certain time. - - for (i = 0; i < CSUITNOREPEAT; i++) - { - if (isentence == m_rgiSuitNoRepeat[i]) - { - // this sentence or group is already in - // the norepeat list - - if (m_rgflSuitNoRepeatTime[i] < gpGlobals->time) - { - // norepeat time has expired, clear it out - m_rgiSuitNoRepeat[i] = 0; - m_rgflSuitNoRepeatTime[i] = 0.0; - iempty = i; - break; - } - else - { - // don't play, still marked as norepeat - return; - } - } - // keep track of empty slot - if (!m_rgiSuitNoRepeat[i]) - iempty = i; - } - - // sentence is not in norepeat list, save if norepeat time was given - - if (iNoRepeatTime) - { - if (iempty < 0) - iempty = RANDOM_LONG(0, CSUITNOREPEAT-1); // pick random slot to take over - m_rgiSuitNoRepeat[iempty] = isentence; - m_rgflSuitNoRepeatTime[iempty] = iNoRepeatTime + gpGlobals->time; - } - - // find empty spot in queue, or overwrite last spot - - m_rgSuitPlayList[m_iSuitPlayNext++] = isentence; - if (m_iSuitPlayNext == CSUITPLAYLIST) - m_iSuitPlayNext = 0; - - if (m_flSuitUpdate <= gpGlobals->time) - { - if (m_flSuitUpdate == 0) - // play queue is empty, don't delay too long before playback - m_flSuitUpdate = gpGlobals->time + SUITFIRSTUPDATETIME; - else - m_flSuitUpdate = gpGlobals->time + SUITUPDATETIME; - } - -} - -/* -================ -CheckPowerups - -Check for turning off powerups - -GLOBALS ASSUMED SET: g_ulModelIndexPlayer -================ -*/ - static void -CheckPowerups(entvars_t *pev) -{ - if (pev->health <= 0) - return; - - pev->modelindex = g_ulModelIndexPlayer; // don't use eyes -} - - -//========================================================= -// UpdatePlayerSound - updates the position of the player's -// reserved sound slot in the sound list. -//========================================================= -void CBasePlayer :: UpdatePlayerSound ( void ) -{ - int iBodyVolume; - int iVolume; - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt :: ClientSoundIndex( edict() ) ); - - if ( !pSound ) - { - ALERT ( at_console, "Client lost reserved sound!\n" ); - return; - } - - pSound->m_iType = bits_SOUND_NONE; - - // now calculate the best target volume for the sound. If the player's weapon - // is louder than his body/movement, use the weapon volume, else, use the body volume. - - if ( FBitSet ( pev->flags, FL_ONGROUND ) ) - { - iBodyVolume = static_cast(pev->velocity.Length()); - - // clamp the noise that can be made by the body, in case a push trigger, - // weapon recoil, or anything shoves the player abnormally fast. - if ( iBodyVolume > 512 ) - { - iBodyVolume = 512; - } - } - else - { - iBodyVolume = 0; - } - - if ( pev->button & IN_JUMP ) - { - iBodyVolume += 100; - } - -// convert player move speed and actions into sound audible by monsters. - if ( m_iWeaponVolume > iBodyVolume ) - { - m_iTargetVolume = m_iWeaponVolume; - - // OR in the bits for COMBAT sound if the weapon is being louder than the player. - pSound->m_iType |= bits_SOUND_COMBAT; - } - else - { - m_iTargetVolume = iBodyVolume; - } - - // decay weapon volume over time so bits_SOUND_COMBAT stays set for a while - m_iWeaponVolume -= static_cast(250 * gpGlobals->frametime); - if ( m_iWeaponVolume < 0 ) - { - iVolume = 0; - } - - - // if target volume is greater than the player sound's current volume, we paste the new volume in - // immediately. If target is less than the current volume, current volume is not set immediately to the - // lower volume, rather works itself towards target volume over time. This gives monsters a much better chance - // to hear a sound, especially if they don't listen every frame. - iVolume = pSound->m_iVolume; - - if ( m_iTargetVolume > iVolume ) - { - iVolume = m_iTargetVolume; - } - else if ( iVolume > m_iTargetVolume ) - { - iVolume -= static_cast(250 * gpGlobals->frametime); - - if ( iVolume < m_iTargetVolume ) - { - iVolume = 0; - } - } - - if ( m_fNoPlayerSound ) - { - // debugging flag, lets players move around and shoot without monsters hearing. - iVolume = 0; - } - - if ( gpGlobals->time > m_flStopExtraSoundTime ) - { - // since the extra sound that a weapon emits only lasts for one client frame, we keep that sound around for a server frame or two - // after actual emission to make sure it gets heard. - m_iExtraSoundTypes = 0; - } - - if ( pSound ) - { - pSound->m_vecOrigin = pev->origin; - pSound->m_iType |= ( bits_SOUND_PLAYER | m_iExtraSoundTypes ); - pSound->m_iVolume = iVolume; - } - - // keep track of virtual muzzle flash - m_iWeaponFlash -= static_cast(256 * gpGlobals->frametime); - if (m_iWeaponFlash < 0) - m_iWeaponFlash = 0; - - //UTIL_MakeVectors ( pev->angles ); - //gpGlobals->v_forward.z = 0; - - // Below are a couple of useful little bits that make it easier to determine just how much noise the - // player is making. - // UTIL_ParticleEffect ( pev->origin + gpGlobals->v_forward * iVolume, g_vecZero, 255, 25 ); - //ALERT ( at_console, "%d/%d\n", iVolume, m_iTargetVolume ); -} - - -void CBasePlayer::PostThink() -{ - if ( g_fGameOver ) - goto pt_end; // intermission or finale - - if (!IsAlive()) - goto pt_end; - - // Handle Tank controlling - if ( m_pTank != 0 ) - { // if they've moved too far from the gun, or selected a weapon, unuse the gun - if ( m_pTank->OnControls( pev ) && !pev->weaponmodel ) - { - m_pTank->Use( this, this, USE_SET, 2 ); // try fire the gun - } - else - { // they've moved off the platform - m_pTank->Use( this, this, USE_OFF, 0 ); - m_pTank = NULL; - } - } - -// do weapon stuff - ItemPostFrame( ); - -// check to see if player landed hard enough to make a sound -// falling farther than half of the maximum safe distance, but not as far a max safe distance will -// play a bootscrape sound, and no damage will be inflicted. Fallling a distance shorter than half -// of maximum safe distance will make no sound. Falling farther than max safe distance will play a -// fallpain sound, and damage will be inflicted based on how far the player fell - - if ( (FBitSet(pev->flags, FL_ONGROUND)) && (pev->health > 0) && m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - // ALERT ( at_console, "%f\n", m_flFallVelocity ); - - if (pev->watertype == CONTENT_WATER) - { - // Did he hit the world or a non-moving entity? - // BUG - this happens all the time in water, especially when - // BUG - water has current force - // if ( !pev->groundentity || VARS(pev->groundentity)->velocity.z == 0 ) - // EMIT_SOUND(ENT(pev), CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM); - } - else if ( m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) - {// after this point, we start doing damage - - float flFallDamage = g_pGameRules->FlPlayerFallDamage( this ); - - if ( flFallDamage > pev->health ) - {//splat - // note: play on item channel because we play footstep landing on body channel - EMIT_SOUND(ENT(pev), CHAN_ITEM, "common/bodysplat.wav", 1, ATTN_NORM); - } - - if ( flFallDamage > 0 ) - { - TakeDamage(VARS(eoNullEntity), VARS(eoNullEntity), flFallDamage, DMG_FALL ); - pev->punchangle.x = 0; - } - } - - if ( IsAlive() ) - { - SetAnimation( PLAYER_WALK ); - } - } - - if (FBitSet(pev->flags, FL_ONGROUND)) - { - if (m_flFallVelocity > 64 && !g_pGameRules->IsMultiplayer()) - { - CSoundEnt::InsertSound ( bits_SOUND_PLAYER, pev->origin, static_cast(m_flFallVelocity), 0.2 ); - // ALERT( at_console, "fall %f\n", m_flFallVelocity ); - } - m_flFallVelocity = 0; - } - - // select the proper animation for the player character - if ( IsAlive() ) - { - if (!pev->velocity.x && !pev->velocity.y) - SetAnimation( PLAYER_IDLE ); - else if ((pev->velocity.x || pev->velocity.y) && (FBitSet(pev->flags, FL_ONGROUND))) - SetAnimation( PLAYER_WALK ); - else if (pev->waterlevel > 1) - SetAnimation( PLAYER_WALK ); - } - - StudioFrameAdvance( ); - CheckPowerups(pev); - - UpdatePlayerSound(); - -pt_end: -#if defined( CLIENT_WEAPONS ) - // Decay timers on weapons - // go through all of the weapons and make a list of the ones to pack - for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pPlayerItem = m_rgpPlayerItems[ i ]; - - while ( pPlayerItem ) - { - CBasePlayerWeapon *gun; - - gun = (CBasePlayerWeapon *)pPlayerItem->GetWeaponPtr(); - - if ( gun && gun->UseDecrement() ) - { - gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); - gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 ); - - if ( gun->m_flTimeWeaponIdle != 1000 ) - { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); - } - - if ( gun->pev->fuser1 != 1000 ) - { - gun->pev->fuser1 = max( gun->pev->fuser1 - gpGlobals->frametime, -0.001 ); - } - - // Only decrement if not flagged as NO_DECREMENT -// if ( gun->m_flPumpTime != 1000 ) - // { - // gun->m_flPumpTime = max( gun->m_flPumpTime - gpGlobals->frametime, -0.001 ); - // } - - } - - pPlayerItem = pPlayerItem->m_pNext; - } - } - } - - m_flNextAttack -= gpGlobals->frametime; - if ( m_flNextAttack < -0.001 ) - m_flNextAttack = -0.001; - - if ( m_flNextAmmoBurn != 1000 ) - { - m_flNextAmmoBurn -= gpGlobals->frametime; - - if ( m_flNextAmmoBurn < -0.001 ) - m_flNextAmmoBurn = -0.001; - } - - if ( m_flAmmoStartCharge != 1000 ) - { - m_flAmmoStartCharge -= gpGlobals->frametime; - - if ( m_flAmmoStartCharge < -0.001 ) - m_flAmmoStartCharge = -0.001; - } -#endif - - // Track button info so we can detect 'pressed' and 'released' buttons next frame - m_afButtonLast = pev->button; -} - - -// checks if the spot is clear of players -BOOL IsSpawnPointValid( CBaseEntity *pPlayer, CBaseEntity *pSpot ) -{ - CBaseEntity *ent = NULL; - - if ( !pSpot->IsTriggered( pPlayer ) ) - { - return FALSE; - } - - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - { - // if ent is a client, don't spawn on 'em - if ( ent->IsPlayer() && ent != pPlayer ) - return FALSE; - } - - return TRUE; -} - - -DLL_GLOBAL CBaseEntity *g_pLastSpawn; -inline int FNullEnt( CBaseEntity *ent ) { return (ent == NULL) || FNullEnt( ent->edict() ); } - -/* -============ -EntSelectSpawnPoint - -Returns the entity to spawn at - -USES AND SETS GLOBAL g_pLastSpawn -============ -*/ -edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) -{ - CBaseEntity *pSpot; - edict_t *player; - - player = pPlayer->edict(); - -// choose a info_player_deathmatch point - if (g_pGameRules->IsCoOp()) - { - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_coop"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - pSpot = UTIL_FindEntityByClassname( g_pLastSpawn, "info_player_start"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - else if ( g_pGameRules->IsDeathmatch() ) - { - pSpot = g_pLastSpawn; - // Randomize the start spot - for ( int i = RANDOM_LONG(1,5); i > 0; i-- ) - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - if ( FNullEnt( pSpot ) ) // skip over the null point - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - - CBaseEntity *pFirstSpot = pSpot; - - do - { - if ( pSpot ) - { - // check if pSpot is valid - if ( IsSpawnPointValid( pPlayer, pSpot ) ) - { - if ( pSpot->pev->origin == Vector( 0, 0, 0 ) ) - { - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - continue; - } - - // if so, go to pSpot - goto ReturnSpot; - } - } - // increment pSpot - pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" ); - } while ( pSpot != pFirstSpot ); // loop if we're not back to the start - - // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there - if ( !FNullEnt( pSpot ) ) - { - CBaseEntity *ent = NULL; - while ( (ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 )) != NULL ) - { - // if ent is a client, kill em (unless they are ourselves) - if ( ent->IsPlayer() && !(ent->edict() == player) ) - ent->TakeDamage( VARS(INDEXENT(0)), VARS(INDEXENT(0)), 300, DMG_GENERIC ); - } - goto ReturnSpot; - } - } - - // If startspot is set, (re)spawn there. - if ( FStringNull( gpGlobals->startspot ) || !strlen(STRING(gpGlobals->startspot))) - { - pSpot = UTIL_FindEntityByClassname(NULL, "info_player_start"); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - else - { - pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) ); - if ( !FNullEnt(pSpot) ) - goto ReturnSpot; - } - -ReturnSpot: - if ( FNullEnt( pSpot ) ) - { - ALERT(at_error, "PutClientInServer: no info_player_start on level"); - return INDEXENT(0); - } - - g_pLastSpawn = pSpot; - return pSpot->edict(); -} - -void CBasePlayer::Spawn( void ) -{ - pev->classname = MAKE_STRING("player"); - pev->health = 100; - pev->armorvalue = 0; - pev->takedamage = DAMAGE_AIM; - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_WALK; - pev->max_health = pev->health; - pev->flags &= FL_PROXY; // keep proxy flag sey by engine - pev->flags |= FL_CLIENT; - pev->air_finished = gpGlobals->time + 12; - pev->dmg = 2; // initial water damage - pev->effects = 0; - pev->deadflag = DEAD_NO; - pev->dmg_take = 0; - pev->dmg_save = 0; - pev->friction = 1.0; - pev->gravity = 1.0; - m_bitsHUDDamage = -1; - m_bitsDamageType = 0; - m_afPhysicsFlags = 0; - m_fLongJump = FALSE;// no longjump module. - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - pev->fov = m_iFOV = 0;// init field of view. - m_iClientFOV = -1; // make sure fov reset is sent - - m_flNextDecalTime = 0;// let this player decal as soon as he spawns. - - m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations - // are recieved by all clients - - m_flTimeStepSound = 0; - m_iStepLeft = 0; - m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. - - m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = UTIL_WeaponTimeBase(); - StartSneaking(); - - m_iFlashBattery = 99; - m_flFlashLightTime = 1; // force first message - -// dont let uninitialized value here hurt the player - m_flFallVelocity = 0; - - g_pGameRules->SetDefaultPlayerTeam( this ); - g_pGameRules->GetPlayerSpawnSpot( this ); - - SET_MODEL(ENT(pev), "models/player.mdl"); - g_ulModelIndexPlayer = pev->modelindex; - pev->sequence = LookupActivity( ACT_IDLE ); - - if ( FBitSet(pev->flags, FL_DUCKING) ) - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - else - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - - pev->view_ofs = VEC_VIEW; - Precache(); - m_HackedGunPos = Vector( 0, 32, 0 ); - - if ( m_iPlayerSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Couldn't alloc player sound slot!\n" ); - } - - m_fNoPlayerSound = FALSE;// normal sound behavior. - - m_pLastItem = NULL; - m_fInitHUD = TRUE; - m_iClientHideHUD = -1; // force this to be recalculated - m_fWeapon = FALSE; - m_pClientActiveItem = NULL; - m_iClientBattery = -1; - - // reset all ammo values to 0 - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - m_rgAmmo[i] = 0; - m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) - } - - m_lastx = m_lasty = 0; - - m_flNextChatTime = gpGlobals->time; - - g_pGameRules->PlayerSpawn( this ); -} - - -void CBasePlayer :: Precache( void ) -{ - // in the event that the player JUST spawned, and the level node graph - // was loaded, fix all of the node graph pointers before the game starts. - - // !!!BUGBUG - now that we have multiplayer, this needs to be moved! - if ( WorldGraph.m_fGraphPresent && !WorldGraph.m_fGraphPointersSet ) - { - if ( !WorldGraph.FSetGraphPointers() ) - { - ALERT ( at_console, "**Graph pointers were not set!\n"); - } - else - { - ALERT ( at_console, "**Graph Pointers Set!\n" ); - } - } - - // SOUNDS / MODELS ARE PRECACHED in ClientPrecache() (game specific) - // because they need to precache before any clients have connected - - // init geiger counter vars during spawn and each time - // we cross a level transition - - m_flgeigerRange = 1000; - m_igeigerRangePrev = 1000; - - m_bitsDamageType = 0; - m_bitsHUDDamage = -1; - - m_iClientBattery = -1; - - m_iTrain = TRAIN_NEW; - - // Make sure any necessary user messages have been registered - LinkUserMessages(); - - m_iUpdateTime = 5; // won't update for 1/2 a second - - if ( gInitHUD ) - m_fInitHUD = TRUE; -} - - -int CBasePlayer::Save( CSave &save ) -{ - if ( !CBaseMonster::Save(save) ) - return 0; - - return save.WriteFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); -} - - -// -// Marks everything as new so the player will resend this to the hud. -// -void CBasePlayer::RenewItems(void) -{ - -} - - -int CBasePlayer::Restore( CRestore &restore ) -{ - if ( !CBaseMonster::Restore(restore) ) - return 0; - - int status = restore.ReadFields( "PLAYER", this, m_playerSaveData, ARRAYSIZE(m_playerSaveData) ); - - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - // landmark isn't present. - if ( !pSaveData->fUseLandmark ) - { - ALERT( at_console, "No Landmark:%s\n", pSaveData->szLandmarkName ); - - // default to normal spawn - edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); - pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); - pev->angles = VARS(pentSpawnSpot)->angles; - } - pev->v_angle.z = 0; // Clear out roll - pev->angles = pev->v_angle; - - pev->fixangle = TRUE; // turn this way immediately - -// Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; - - g_ulModelIndexPlayer = pev->modelindex; - - if ( FBitSet(pev->flags, FL_DUCKING) ) - { - // Use the crouch HACK - //FixPlayerCrouchStuck( edict() ); - // Don't need to do this with new player prediction code. - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); - } - else - { - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - } - - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "hl", "1" ); - - if ( m_fLongJump ) - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "1" ); - } - else - { - g_engfuncs.pfnSetPhysicsKeyValue( edict(), "slj", "0" ); - } - - RenewItems(); - -#if defined( CLIENT_WEAPONS ) - // HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it - // as just a counter. Ideally, this needs its own variable that's saved as a plain float. - // Barring that, we clear it out here instead of using the incorrect restored time value. - m_flNextAttack = UTIL_WeaponTimeBase(); -#endif - - return status; -} - - - -void CBasePlayer::SelectNextItem( int iItem ) -{ - CBasePlayerItem *pItem; - - pItem = m_rgpPlayerItems[ iItem ]; - - if (!pItem) - return; - - if (pItem == m_pActiveItem) - { - // select the next one in the chain - pItem = m_pActiveItem->m_pNext; - if (! pItem) - { - return; - } - - CBasePlayerItem *pLast; - pLast = pItem; - while (pLast->m_pNext) - pLast = pLast->m_pNext; - - // relink chain - pLast->m_pNext = m_pActiveItem; - m_pActiveItem->m_pNext = NULL; - m_rgpPlayerItems[ iItem ] = pItem; - } - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - -void CBasePlayer::SelectItem(const char *pstr) -{ - if (!pstr) - return; - - CBasePlayerItem *pItem = NULL; - - for (int i = 0; i < MAX_ITEM_TYPES; i++) - { - if (m_rgpPlayerItems[i]) - { - pItem = m_rgpPlayerItems[i]; - - while (pItem) - { - if (FClassnameIs(pItem->pev, pstr)) - break; - pItem = pItem->m_pNext; - } - } - - if (pItem) - break; - } - - if (!pItem) - return; - - - if (pItem == m_pActiveItem) - return; - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - m_pLastItem = m_pActiveItem; - m_pActiveItem = pItem; - - if (m_pActiveItem) - { - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); - } -} - - -void CBasePlayer::SelectLastItem(void) -{ - if (!m_pLastItem) - { - return; - } - - if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) - { - return; - } - - ResetAutoaim( ); - - // FIX, this needs to queue them up and delay - if (m_pActiveItem) - m_pActiveItem->Holster( ); - - CBasePlayerItem *pTemp = m_pActiveItem; - m_pActiveItem = m_pLastItem; - m_pLastItem = pTemp; - m_pActiveItem->Deploy( ); - m_pActiveItem->UpdateItemInfo( ); -} - -//============================================== -// HasWeapons - do I have any weapons at all? -//============================================== -BOOL CBasePlayer::HasWeapons( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return TRUE; - } - } - - return FALSE; -} - -void CBasePlayer::SelectPrevItem( int iItem ) -{ -} - - -const char *CBasePlayer::TeamID( void ) -{ - if ( pev == NULL ) // Not fully connected yet - return ""; - - // return their team name - return m_szTeamName; -} - - -//============================================== -// !!!UNDONE:ultra temporary SprayCan entity to apply -// decal frame at a time. For PreAlpha CD -//============================================== -class CSprayCan : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Think( void ); - - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -void CSprayCan::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - pev->frame = 0; - - pev->nextthink = gpGlobals->time + 0.1; - EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/sprayer.wav", 1, ATTN_NORM); -} - -void CSprayCan::Think( void ) -{ - TraceResult tr; - int playernum; - int nFrames; - CBasePlayer *pPlayer; - - pPlayer = (CBasePlayer *)GET_PRIVATE(pev->owner); - - if (pPlayer) - nFrames = pPlayer->GetCustomDecalFrames(); - else - nFrames = -1; - - playernum = ENTINDEX(pev->owner); - - // ALERT(at_console, "Spray by player %i, %i of %i\n", playernum, (int)(pev->frame + 1), nFrames); - - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - // No customization present. - if (nFrames == -1) - { - UTIL_DecalTrace( &tr, DECAL_LAMBDA6 ); - UTIL_Remove( this ); - } - else - { - UTIL_PlayerDecalTrace( &tr, playernum, static_cast(pev->frame), TRUE ); - // Just painted last custom frame. - if ( pev->frame++ >= (nFrames - 1)) - UTIL_Remove( this ); - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -class CBloodSplat : public CBaseEntity -{ -public: - void Spawn ( entvars_t *pevOwner ); - void Spray ( void ); -}; - -void CBloodSplat::Spawn ( entvars_t *pevOwner ) -{ - pev->origin = pevOwner->origin + Vector ( 0 , 0 , 32 ); - pev->angles = pevOwner->v_angle; - pev->owner = ENT(pevOwner); - - SetThink ( &CBloodSplat::Spray ); - pev->nextthink = gpGlobals->time + 0.1; -} - -void CBloodSplat::Spray ( void ) -{ - TraceResult tr; - - if ( g_Language != LANGUAGE_GERMAN ) - { - UTIL_MakeVectors(pev->angles); - UTIL_TraceLine ( pev->origin, pev->origin + gpGlobals->v_forward * 128, ignore_monsters, pev->owner, & tr); - - UTIL_BloodDecalTrace( &tr, BLOOD_COLOR_RED ); - } - SetThink ( &CBloodSplat::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - -//============================================== - - - -void CBasePlayer::GiveNamedItem( const char *pszName ) -{ - edict_t *pent; - - int istr = MAKE_STRING(pszName); - - pent = CREATE_NAMED_ENTITY(istr); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in GiveNamedItem!\n" ); - return; - } - VARS( pent )->origin = pev->origin; - pent->v.spawnflags |= SF_NORESPAWN; - - DispatchSpawn( pent ); - DispatchTouch( pent, ENT( pev ) ); -} - - - -CBaseEntity *FindEntityForward( CBaseEntity *pMe ) -{ - TraceResult tr; - - UTIL_MakeVectors(pMe->pev->v_angle); - UTIL_TraceLine(pMe->pev->origin + pMe->pev->view_ofs,pMe->pev->origin + pMe->pev->view_ofs + gpGlobals->v_forward * 8192,dont_ignore_monsters, pMe->edict(), &tr ); - if ( tr.flFraction != 1.0 && !FNullEnt( tr.pHit) ) - { - CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit ); - return pHit; - } - return NULL; -} - - -BOOL CBasePlayer :: FlashlightIsOn( void ) -{ - return FBitSet(pev->effects, EF_DIMLIGHT); -} - - -void CBasePlayer :: FlashlightTurnOn( void ) -{ - if ( !g_pGameRules->FAllowFlashlight() ) - { - return; - } - - if ( (pev->weapons & (1<effects, EF_DIMLIGHT); - MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(1); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; - - } -} - - -void CBasePlayer :: FlashlightTurnOff( void ) -{ - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, SOUND_FLASHLIGHT_OFF, 1.0, ATTN_NORM, 0, PITCH_NORM ); - ClearBits(pev->effects, EF_DIMLIGHT); - MESSAGE_BEGIN( MSG_ONE, gmsgFlashlight, NULL, pev ); - WRITE_BYTE(0); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; - -} - -/* -=============== -ForceClientDllUpdate - -When recording a demo, we need to have the server tell us the entire client state -so that the client side .dll can behave correctly. -Reset stuff so that the state is transmitted. -=============== -*/ -void CBasePlayer :: ForceClientDllUpdate( void ) -{ - m_iClientHealth = -1; - m_iClientBattery = -1; - m_iTrain |= TRAIN_NEW; // Force new train message. - m_fWeapon = FALSE; // Force weapon send - m_fKnownItem = FALSE; // Force weaponinit messages. - m_fInitHUD = TRUE; // Force HUD gmsgResetHUD message - - // Now force all the necessary messages - // to be sent. - UpdateClientData(); -} - -/* -============ -ImpulseCommands -============ -*/ -extern float g_flWeaponCheat; - -void CBasePlayer::ImpulseCommands( ) -{ - TraceResult tr;// UNDONE: kill me! This is temporary for PreAlpha CDs - - // Handle use events - PlayerUse(); - - int iImpulse = (int)pev->impulse; - switch (iImpulse) - { - case 99: - { - - int iOn; - - if (!gmsgLogo) - { - iOn = 1; - gmsgLogo = REG_USER_MSG("Logo", 1); - } - else - { - iOn = 0; - } - - ASSERT( gmsgLogo > 0 ); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgLogo, NULL, pev ); - WRITE_BYTE(iOn); - MESSAGE_END(); - - if(!iOn) - gmsgLogo = 0; - break; - } - case 100: - // temporary flashlight for level designers - if ( FlashlightIsOn() ) - { - FlashlightTurnOff(); - } - else - { - FlashlightTurnOn(); - } - break; - - case 201:// paint decal - - if ( gpGlobals->time < m_flNextDecalTime ) - { - // too early! - break; - } - - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); - - if ( tr.flFraction != 1.0 ) - {// line hit something, so paint a decal - m_flNextDecalTime = gpGlobals->time + decalfrequency.value; - CSprayCan *pCan = GetClassPtr((CSprayCan *)NULL); - pCan->Spawn( pev ); - } - - break; - - default: - // check all of the cheat impulse commands now - CheatImpulseCommands( iImpulse ); - break; - } - - pev->impulse = 0; -} - -//========================================================= -//========================================================= -void CBasePlayer::CheatImpulseCommands( int iImpulse ) -{ -#if !defined( HLDEMO_BUILD ) - if ( g_flWeaponCheat == 0.0 ) - { - return; - } - - CBaseEntity *pEntity; - TraceResult tr; - - switch ( iImpulse ) - { - case 76: - { - if (!giPrecacheGrunt) - { - giPrecacheGrunt = 1; - ALERT(at_console, "You must now restart to use Grunt-o-matic.\n"); - } - else - { - UTIL_MakeVectors( Vector( 0, pev->v_angle.y, 0 ) ); - Create("monster_human_grunt", pev->origin + gpGlobals->v_forward * 128, pev->angles); - } - break; - } - - - case 101: - gEvilImpulse101 = TRUE; - GiveNamedItem( "item_suit" ); - GiveNamedItem( "item_battery" ); - GiveNamedItem( "weapon_crowbar" ); - GiveNamedItem( "weapon_9mmhandgun" ); - GiveNamedItem( "ammo_9mmclip" ); - GiveNamedItem( "weapon_shotgun" ); - GiveNamedItem( "ammo_buckshot" ); - GiveNamedItem( "weapon_9mmAR" ); - GiveNamedItem( "ammo_9mmAR" ); - GiveNamedItem( "ammo_ARgrenades" ); - GiveNamedItem( "weapon_handgrenade" ); - GiveNamedItem( "weapon_tripmine" ); -#ifndef OEM_BUILD - GiveNamedItem( "weapon_357" ); - GiveNamedItem( "ammo_357" ); - GiveNamedItem( "weapon_crossbow" ); - GiveNamedItem( "ammo_crossbow" ); - GiveNamedItem( "weapon_egon" ); - GiveNamedItem( "weapon_gauss" ); - GiveNamedItem( "ammo_gaussclip" ); - GiveNamedItem( "weapon_rpg" ); - GiveNamedItem( "ammo_rpgclip" ); - GiveNamedItem( "weapon_satchel" ); - GiveNamedItem( "weapon_snark" ); - GiveNamedItem( "weapon_hornetgun" ); -#endif - gEvilImpulse101 = FALSE; - break; - - case 102: - // Gibbage!!! - CGib::SpawnRandomGibs( pev, 1, 1 ); - break; - - case 103: - // What the hell are you doing? - pEntity = FindEntityForward( this ); - if ( pEntity ) - { - CBaseMonster *pMonster = pEntity->MyMonsterPointer(); - if ( pMonster ) - pMonster->ReportAIState(); - } - break; - - case 104: - // Dump all of the global state varaibles (and global entity names) - gGlobalState.DumpGlobals(); - break; - - case 105:// player makes no sound for monsters to hear. - { - if ( m_fNoPlayerSound ) - { - ALERT ( at_console, "Player is audible\n" ); - m_fNoPlayerSound = FALSE; - } - else - { - ALERT ( at_console, "Player is silent\n" ); - m_fNoPlayerSound = TRUE; - } - break; - } - - case 106: - // Give me the classname and targetname of this entity. - pEntity = FindEntityForward( this ); - if ( pEntity ) - { - ALERT ( at_console, "Classname: %s", STRING( pEntity->pev->classname ) ); - - if ( !FStringNull ( pEntity->pev->targetname ) ) - { - ALERT ( at_console, " - Targetname: %s\n", STRING( pEntity->pev->targetname ) ); - } - else - { - ALERT ( at_console, " - TargetName: No Targetname\n" ); - } - - ALERT ( at_console, "Model: %s\n", STRING( pEntity->pev->model ) ); - if ( pEntity->pev->globalname ) - ALERT ( at_console, "Globalname: %s\n", STRING( pEntity->pev->globalname ) ); - } - break; - - case 107: - { - TraceResult tr; - - edict_t *pWorld = g_engfuncs.pfnPEntityOfEntIndex( 0 ); - - Vector start = pev->origin + pev->view_ofs; - Vector end = start + gpGlobals->v_forward * 1024; - UTIL_TraceLine( start, end, ignore_monsters, edict(), &tr ); - if ( tr.pHit ) - pWorld = tr.pHit; - const char *pTextureName = TRACE_TEXTURE( pWorld, start, end ); - if ( pTextureName ) - ALERT( at_console, "Texture: %s\n", pTextureName ); - } - break; - case 195:// show shortest paths for entire level to nearest node - { - Create("node_viewer_fly", pev->origin, pev->angles); - } - break; - case 196:// show shortest paths for entire level to nearest node - { - Create("node_viewer_large", pev->origin, pev->angles); - } - break; - case 197:// show shortest paths for entire level to nearest node - { - Create("node_viewer_human", pev->origin, pev->angles); - } - break; - case 199:// show nearest node and all connections - { - ALERT ( at_console, "%d\n", WorldGraph.FindNearestNode ( pev->origin, bits_NODE_GROUP_REALM ) ); - WorldGraph.ShowNodeConnections ( WorldGraph.FindNearestNode ( pev->origin, bits_NODE_GROUP_REALM ) ); - } - break; - case 202:// Random blood splatter - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine ( pev->origin + pev->view_ofs, pev->origin + pev->view_ofs + gpGlobals->v_forward * 128, ignore_monsters, ENT(pev), & tr); - - if ( tr.flFraction != 1.0 ) - {// line hit something, so paint a decal - CBloodSplat *pBlood = GetClassPtr((CBloodSplat *)NULL); - pBlood->Spawn( pev ); - } - break; - case 203:// remove creature. - pEntity = FindEntityForward( this ); - if ( pEntity ) - { - if ( pEntity->pev->takedamage ) - pEntity->SetThink(&CBaseEntity::SUB_Remove); - } - break; - } -#endif // HLDEMO_BUILD -} - -// -// Add a weapon to the player (Item == Weapon == Selectable Object) -// -int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) -{ - CBasePlayerItem *pInsert; - - pInsert = m_rgpPlayerItems[pItem->iItemSlot()]; - - while (pInsert) - { - if (FClassnameIs( pInsert->pev, STRING( pItem->pev->classname) )) - { - if (pItem->AddDuplicate( pInsert )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - // ugly hack to update clip w/o an update clip message - pInsert->UpdateItemInfo( ); - if (m_pActiveItem) - m_pActiveItem->UpdateItemInfo( ); - - pItem->Kill( ); - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; - } - pInsert = pInsert->m_pNext; - } - - - if (pItem->AddToPlayer( this )) - { - g_pGameRules->PlayerGotWeapon ( this, pItem ); - pItem->CheckRespawn(); - - pItem->m_pNext = m_rgpPlayerItems[pItem->iItemSlot()]; - m_rgpPlayerItems[pItem->iItemSlot()] = pItem; - - // should we switch to this item? - if ( g_pGameRules->FShouldSwitchWeapon( this, pItem ) ) - { - SwitchWeapon( pItem ); - } - - return TRUE; - } - else if (gEvilImpulse101) - { - // FIXME: remove anyway for deathmatch testing - pItem->Kill( ); - } - return FALSE; -} - - - -int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) -{ - if (m_pActiveItem == pItem) - { - ResetAutoaim( ); - pItem->Holster( ); - pItem->pev->nextthink = 0;// crowbar may be trying to swing again, etc. - pItem->SetThink( NULL ); - m_pActiveItem = NULL; - pev->viewmodel = 0; - pev->weaponmodel = 0; - } - else if ( m_pLastItem == pItem ) - m_pLastItem = NULL; - - CBasePlayerItem *pPrev = m_rgpPlayerItems[pItem->iItemSlot()]; - - if (pPrev == pItem) - { - m_rgpPlayerItems[pItem->iItemSlot()] = pItem->m_pNext; - return TRUE; - } - else - { - while (pPrev && pPrev->m_pNext != pItem) - { - pPrev = pPrev->m_pNext; - } - if (pPrev) - { - pPrev->m_pNext = pItem->m_pNext; - return TRUE; - } - } - return FALSE; -} - - -// -// Returns the unique ID for the ammo, or -1 if error -// -int CBasePlayer :: GiveAmmo( int iCount, const char *szName, int iMax ) -{ - if ( !szName ) - { - // no ammo. - return -1; - } - - if ( !g_pGameRules->CanHaveAmmo( this, szName, iMax ) ) - { - // game rules say I can't have any more of this ammo type. - return -1; - } - - int i = 0; - - i = GetAmmoIndex( szName ); - - if ( i < 0 || i >= MAX_AMMO_SLOTS ) - return -1; - - int iAdd = min( iCount, iMax - m_rgAmmo[i] ); - if ( iAdd < 1 ) - return i; - - m_rgAmmo[ i ] += iAdd; - - - if ( gmsgAmmoPickup ) // make sure the ammo messages have been linked first - { - // Send the message that ammo has been picked up - MESSAGE_BEGIN( MSG_ONE, gmsgAmmoPickup, NULL, pev ); - WRITE_BYTE( GetAmmoIndex(szName) ); // ammo ID - WRITE_BYTE( iAdd ); // amount - MESSAGE_END(); - } - - TabulateAmmo(); - - return i; -} - - -/* -============ -ItemPreFrame - -Called every frame by the player PreThink -============ -*/ -void CBasePlayer::ItemPreFrame() -{ -#if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) -#else - if ( gpGlobals->time < m_flNextAttack ) -#endif - { - return; - } - - if (!m_pActiveItem) - return; - - m_pActiveItem->ItemPreFrame( ); -} - - -/* -============ -ItemPostFrame - -Called every frame by the player PostThink -============ -*/ -void CBasePlayer::ItemPostFrame() -{ - // check if the player is using a tank - if ( m_pTank != 0 ) - return; - -#if defined( CLIENT_WEAPONS ) - if ( m_flNextAttack > 0 ) -#else - if ( gpGlobals->time < m_flNextAttack ) -#endif - { - return; - } - - ImpulseCommands(); - - if (!m_pActiveItem) - return; - - m_pActiveItem->ItemPostFrame( ); -} - -int CBasePlayer::AmmoInventory( int iAmmoIndex ) -{ - if (iAmmoIndex == -1) - { - return -1; - } - - return m_rgAmmo[ iAmmoIndex ]; -} - -int CBasePlayer::GetAmmoIndex(const char *psz) -{ - int i; - - if (!psz) - return -1; - - for (i = 1; i < MAX_AMMO_SLOTS; i++) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName ) - continue; - - if (stricmp( psz, CBasePlayerItem::AmmoInfoArray[i].pszName ) == 0) - return i; - } - - return -1; -} - -// Called from UpdateClientData -// makes sure the client has all the necessary ammo info, if values have changed -void CBasePlayer::SendAmmoUpdate(void) -{ - for (int i=0; i < MAX_AMMO_SLOTS;i++) - { - if (m_rgAmmo[i] != m_rgAmmoLast[i]) - { - m_rgAmmoLast[i] = m_rgAmmo[i]; - - ASSERT( m_rgAmmo[i] >= 0 ); - ASSERT( m_rgAmmo[i] < 255 ); - - // send "Ammo" update message - MESSAGE_BEGIN( MSG_ONE, gmsgAmmoX, NULL, pev ); - WRITE_BYTE( i ); - WRITE_BYTE( max( min( m_rgAmmo[i], 254 ), 0 ) ); // clamp the value to one byte - MESSAGE_END(); - } - } -} - -/* -========================================================= - UpdateClientData - -resends any changed player HUD info to the client. -Called every frame by PlayerPreThink -Also called at start of demo recording and playback by -ForceClientDllUpdate to ensure the demo gets messages -reflecting all of the HUD state info. -========================================================= -*/ -void CBasePlayer :: UpdateClientData( void ) -{ - if (m_fInitHUD) - { - m_fInitHUD = FALSE; - gInitHUD = FALSE; - - MESSAGE_BEGIN( MSG_ONE, gmsgResetHUD, NULL, pev ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - - if ( !m_fGameHUDInitialized ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgInitHUD, NULL, pev ); - MESSAGE_END(); - - g_pGameRules->InitHUD( this ); - m_fGameHUDInitialized = TRUE; - - m_iObserverLastMode = OBS_ROAMING; - - if ( g_pGameRules->IsMultiplayer() ) - { - FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); - } - } - - FireTargets( "game_playerspawn", this, this, USE_TOGGLE, 0 ); - - InitStatusBar(); - } - - if ( m_iHideHUD != m_iClientHideHUD ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgHideWeapon, NULL, pev ); - WRITE_BYTE( m_iHideHUD ); - MESSAGE_END(); - - m_iClientHideHUD = m_iHideHUD; - } - - if ( m_iFOV != m_iClientFOV ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); - WRITE_BYTE( m_iFOV ); - MESSAGE_END(); - - // cache FOV change at end of function, so weapon updates can see that FOV has changed - } - - // HACKHACK -- send the message to display the game title - if (gDisplayTitle) - { - MESSAGE_BEGIN( MSG_ONE, gmsgShowGameTitle, NULL, pev ); - WRITE_BYTE( 0 ); - MESSAGE_END(); - gDisplayTitle = 0; - } - - if (pev->health != m_iClientHealth) - { -#define clamp( val, min, max ) ( ((val) > (max)) ? (max) : ( ((val) < (min)) ? (min) : (val) ) ) - int iHealth = clamp( pev->health, 0, 255 ); // make sure that no negative health values are sent - if ( pev->health > 0.0f && pev->health <= 1.0f ) - iHealth = 1; - - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); - WRITE_BYTE( iHealth ); - MESSAGE_END(); - - m_iClientHealth = static_cast(pev->health); - } - - - if (pev->armorvalue != m_iClientBattery) - { - m_iClientBattery = static_cast(pev->armorvalue); - - ASSERT( gmsgBattery > 0 ); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgBattery, NULL, pev ); - WRITE_SHORT( (int)pev->armorvalue); - MESSAGE_END(); - } - - if (pev->dmg_take || pev->dmg_save || m_bitsHUDDamage != m_bitsDamageType) - { - // Comes from inside me if not set - Vector damageOrigin = pev->origin; - // send "damage" message - // causes screen to flash, and pain compass to show direction of damage - edict_t *other = pev->dmg_inflictor; - if ( other ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(other); - if ( pEntity ) - damageOrigin = pEntity->Center(); - } - - // only send down damage type that have hud art - int visibleDamageBits = m_bitsDamageType & DMG_SHOWNHUD; - - MESSAGE_BEGIN( MSG_ONE, gmsgDamage, NULL, pev ); - WRITE_BYTE( static_cast(pev->dmg_save) ); - WRITE_BYTE( static_cast(pev->dmg_take) ); - WRITE_LONG( visibleDamageBits ); - WRITE_COORD( damageOrigin.x ); - WRITE_COORD( damageOrigin.y ); - WRITE_COORD( damageOrigin.z ); - MESSAGE_END(); - - pev->dmg_take = 0; - pev->dmg_save = 0; - m_bitsHUDDamage = m_bitsDamageType; - - // Clear off non-time-based damage indicators - m_bitsDamageType &= DMG_TIMEBASED; - } - - // Update Flashlight - if ((m_flFlashLightTime) && (m_flFlashLightTime <= gpGlobals->time)) - { - if (FlashlightIsOn()) - { - if (m_iFlashBattery) - { - m_flFlashLightTime = FLASH_DRAIN_TIME + gpGlobals->time; - m_iFlashBattery--; - - if (!m_iFlashBattery) - FlashlightTurnOff(); - } - } - else - { - if (m_iFlashBattery < 100) - { - m_flFlashLightTime = FLASH_CHARGE_TIME + gpGlobals->time; - m_iFlashBattery++; - } - else - m_flFlashLightTime = 0; - } - - MESSAGE_BEGIN( MSG_ONE, gmsgFlashBattery, NULL, pev ); - WRITE_BYTE(m_iFlashBattery); - MESSAGE_END(); - } - - - if (m_iTrain & TRAIN_NEW) - { - ASSERT( gmsgTrain > 0 ); - // send "health" update message - MESSAGE_BEGIN( MSG_ONE, gmsgTrain, NULL, pev ); - WRITE_BYTE(m_iTrain & 0xF); - MESSAGE_END(); - - m_iTrain &= ~TRAIN_NEW; - } - - // - // New Weapon? - // - if (!m_fKnownItem) - { - m_fKnownItem = TRUE; - - // WeaponInit Message - // byte = # of weapons - // - // for each weapon: - // byte name str length (not including null) - // bytes... name - // byte Ammo Type - // byte Ammo2 Type - // byte bucket - // byte bucket pos - // byte flags - // ???? Icons - - // Send ALL the weapon info now - int i; - - for (i = 0; i < MAX_WEAPONS; i++) - { - ItemInfo& II = CBasePlayerItem::ItemInfoArray[i]; - - if ( !II.iId ) - continue; - - const char *pszName; - if (!II.pszName) - pszName = "Empty"; - else - pszName = II.pszName; - - MESSAGE_BEGIN( MSG_ONE, gmsgWeaponList, NULL, pev ); - WRITE_STRING(pszName); // string weapon name - WRITE_BYTE(GetAmmoIndex(II.pszAmmo1)); // byte Ammo Type - WRITE_BYTE(II.iMaxAmmo1); // byte Max Ammo 1 - WRITE_BYTE(GetAmmoIndex(II.pszAmmo2)); // byte Ammo2 Type - WRITE_BYTE(II.iMaxAmmo2); // byte Max Ammo 2 - WRITE_BYTE(II.iSlot); // byte bucket - WRITE_BYTE(II.iPosition); // byte bucket pos - WRITE_BYTE(II.iId); // byte id (bit index into pev->weapons) - WRITE_BYTE(II.iFlags); // byte Flags - MESSAGE_END(); - } - } - - - SendAmmoUpdate(); - - // Update all the items - for ( int i = 0; i < MAX_ITEM_TYPES; i++ ) - { - if ( m_rgpPlayerItems[i] ) // each item updates it's successors - m_rgpPlayerItems[i]->UpdateClientData( this ); - } - - // Cache and client weapon change - m_pClientActiveItem = m_pActiveItem; - m_iClientFOV = m_iFOV; - - // Update Status Bar - if ( m_flNextSBarUpdateTime < gpGlobals->time ) - { - UpdateStatusBar(); - m_flNextSBarUpdateTime = gpGlobals->time + 0.2; - } -} - - -//========================================================= -// FBecomeProne - Overridden for the player to set the proper -// physics flags when a barnacle grabs player. -//========================================================= -BOOL CBasePlayer :: FBecomeProne ( void ) -{ - m_afPhysicsFlags |= PFLAG_ONBARNACLE; - return TRUE; -} - -//========================================================= -// BarnacleVictimBitten - bad name for a function that is called -// by Barnacle victims when the barnacle pulls their head -// into its mouth. For the player, just die. -//========================================================= -void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) -{ - TakeDamage ( pevBarnacle, pevBarnacle, pev->health + pev->armorvalue, DMG_SLASH | DMG_ALWAYSGIB ); -} - -//========================================================= -// BarnacleVictimReleased - overridden for player who has -// physics flags concerns. -//========================================================= -void CBasePlayer :: BarnacleVictimReleased ( void ) -{ - m_afPhysicsFlags &= ~PFLAG_ONBARNACLE; -} - - -//========================================================= -// Illumination -// return player light level plus virtual muzzle flash -//========================================================= -int CBasePlayer :: Illumination( void ) -{ - int iIllum = CBaseEntity::Illumination( ); - - iIllum += m_iWeaponFlash; - if (iIllum > 255) - return 255; - return iIllum; -} - - -void CBasePlayer :: EnableControl(BOOL fControl) -{ - if (!fControl) - pev->flags |= FL_FROZEN; - else - pev->flags &= ~FL_FROZEN; - -} - - -#define DOT_1DEGREE 0.9998476951564 -#define DOT_2DEGREE 0.9993908270191 -#define DOT_3DEGREE 0.9986295347546 -#define DOT_4DEGREE 0.9975640502598 -#define DOT_5DEGREE 0.9961946980917 -#define DOT_6DEGREE 0.9945218953683 -#define DOT_7DEGREE 0.9925461516413 -#define DOT_8DEGREE 0.9902680687416 -#define DOT_9DEGREE 0.9876883405951 -#define DOT_10DEGREE 0.9848077530122 -#define DOT_15DEGREE 0.9659258262891 -#define DOT_20DEGREE 0.9396926207859 -#define DOT_25DEGREE 0.9063077870367 - -//========================================================= -// Autoaim -// set crosshair position to point to enemey -//========================================================= -Vector CBasePlayer :: GetAutoaimVector( float flDelta ) -{ - if (g_iSkillLevel == SKILL_HARD) - { - UTIL_MakeVectors( pev->v_angle + pev->punchangle ); - return gpGlobals->v_forward; - } - - Vector vecSrc = GetGunPosition( ); - float flDist = 8192; - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (1 || g_iSkillLevel == SKILL_MEDIUM) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - // flDelta *= 0.5; - } - - BOOL m_fOldTargeting = m_fOnTarget; - Vector angles = AutoaimDeflection(vecSrc, flDist, flDelta ); - - // update ontarget if changed - if ( !g_pGameRules->AllowAutoTargetCrosshair() ) - m_fOnTarget = 0; - else if (m_fOldTargeting != m_fOnTarget) - { - m_pActiveItem->UpdateItemInfo( ); - } - - if (angles.x > 180) - angles.x -= 360; - if (angles.x < -180) - angles.x += 360; - if (angles.y > 180) - angles.y -= 360; - if (angles.y < -180) - angles.y += 360; - - if (angles.x > 25) - angles.x = 25; - if (angles.x < -25) - angles.x = -25; - if (angles.y > 12) - angles.y = 12; - if (angles.y < -12) - angles.y = -12; - - - // always use non-sticky autoaim - // UNDONE: use sever variable to chose! - if (0 || g_iSkillLevel == SKILL_EASY) - { - m_vecAutoAim = m_vecAutoAim * 0.67 + angles * 0.33; - } - else - { - m_vecAutoAim = angles * 0.9; - } - - // m_vecAutoAim = m_vecAutoAim * 0.99; - - // Don't send across network if sv_aim is 0 - if ( g_psv_aim->value != 0 ) - { - if ( m_vecAutoAim.x != m_lastx || - m_vecAutoAim.y != m_lasty ) - { - SET_CROSSHAIRANGLE( edict(), -m_vecAutoAim.x, m_vecAutoAim.y ); - - m_lastx = static_cast(m_vecAutoAim.x); - m_lasty = static_cast(m_vecAutoAim.y); - } - } - - // ALERT( at_console, "%f %f\n", angles.x, angles.y ); - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - return gpGlobals->v_forward; -} - - -Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - float bestdot; - Vector bestdir; - edict_t *bestent; - TraceResult tr; - - if ( g_psv_aim->value == 0 ) - { - m_fOnTarget = FALSE; - return g_vecZero; - } - - UTIL_MakeVectors( pev->v_angle + pev->punchangle + m_vecAutoAim ); - - // try all possible entities - bestdir = gpGlobals->v_forward; - bestdot = flDelta; // +- 10 degrees - bestent = NULL; - - m_fOnTarget = FALSE; - - UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, dont_ignore_monsters, edict(), &tr ); - - - if ( tr.pHit && tr.pHit->v.takedamage != DAMAGE_NO) - { - // don't look through water - if (!((pev->waterlevel != 3 && tr.pHit->v.waterlevel == 3) - || (pev->waterlevel == 3 && tr.pHit->v.waterlevel == 0))) - { - if (tr.pHit->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return m_vecAutoAim; - } - } - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - Vector center; - Vector dir; - float dot; - - if ( pEdict->free ) // Not in use - continue; - - if (pEdict->v.takedamage != DAMAGE_AIM) - continue; - if (pEdict == edict()) - continue; -// if (pev->team > 0 && pEdict->v.team == pev->team) -// continue; // don't aim at teammate - if ( !g_pGameRules->ShouldAutoAim( this, pEdict ) ) - continue; - - pEntity = Instance( pEdict ); - if (pEntity == NULL) - continue; - - if (!pEntity->IsAlive()) - continue; - - // don't look through water - if ((pev->waterlevel != 3 && pEntity->pev->waterlevel == 3) - || (pev->waterlevel == 3 && pEntity->pev->waterlevel == 0)) - continue; - - center = pEntity->BodyTarget( vecSrc ); - - dir = (center - vecSrc).Normalize( ); - - // make sure it's in front of the player - if (DotProduct (dir, gpGlobals->v_forward ) < 0) - continue; - - dot = fabs( DotProduct (dir, gpGlobals->v_right ) ) - + fabs( DotProduct (dir, gpGlobals->v_up ) ) * 0.5; - - // tweek for distance - dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist); - - if (dot > bestdot) - continue; // to far to turn - - UTIL_TraceLine( vecSrc, center, dont_ignore_monsters, edict(), &tr ); - if (tr.flFraction != 1.0 && tr.pHit != pEdict) - { - // ALERT( at_console, "hit %s, can't see %s\n", STRING( tr.pHit->v.classname ), STRING( pEdict->v.classname ) ); - continue; - } - - // don't shoot at friends - if (IRelationship( pEntity ) < 0) - { - if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch()) - // ALERT( at_console, "friend\n"); - continue; - } - - // can shoot at this one - bestdot = dot; - bestent = pEdict; - bestdir = dir; - } - - if (bestent) - { - bestdir = UTIL_VecToAngles (bestdir); - bestdir.x = -bestdir.x; - bestdir = bestdir - pev->v_angle - pev->punchangle; - - if (bestent->v.takedamage == DAMAGE_AIM) - m_fOnTarget = TRUE; - - return bestdir; - } - - return Vector( 0, 0, 0 ); -} - - -void CBasePlayer :: ResetAutoaim( ) -{ - if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0) - { - m_vecAutoAim = Vector( 0, 0, 0 ); - SET_CROSSHAIRANGLE( edict(), 0, 0 ); - } - m_fOnTarget = FALSE; -} - -/* -============= -SetCustomDecalFrames - - UNDONE: Determine real frame limit, 8 is a placeholder. - Note: -1 means no custom frames present. -============= -*/ -void CBasePlayer :: SetCustomDecalFrames( int nFrames ) -{ - if (nFrames > 0 && - nFrames < 8) - m_nCustomSprayFrames = nFrames; - else - m_nCustomSprayFrames = -1; -} - -/* -============= -GetCustomDecalFrames - - Returns the # of custom frames this player's custom clan logo contains. -============= -*/ -int CBasePlayer :: GetCustomDecalFrames( void ) -{ - return m_nCustomSprayFrames; -} - - -//========================================================= -// DropPlayerItem - drop the named item, or if no name, -// the active item. -//========================================================= -void CBasePlayer::DropPlayerItem ( char *pszItemName ) -{ - if ( !g_pGameRules->IsMultiplayer() || (weaponstay.value > 0) ) - { - // no dropping in single player. - return; - } - - if ( !strlen( pszItemName ) ) - { - // if this string has no length, the client didn't type a name! - // assume player wants to drop the active item. - // make the string null to make future operations in this function easier - pszItemName = NULL; - } - - CBasePlayerItem *pWeapon; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - if ( pszItemName ) - { - // try to match by name. - if ( !strcmp( pszItemName, STRING( pWeapon->pev->classname ) ) ) - { - // match! - break; - } - } - else - { - // trying to drop active item - if ( pWeapon == m_pActiveItem ) - { - // active item! - break; - } - } - - pWeapon = pWeapon->m_pNext; - } - - - // if we land here with a valid pWeapon pointer, that's because we found the - // item we want to drop and hit a BREAK; pWeapon is the item. - if ( pWeapon ) - { - if ( !g_pGameRules->GetNextBestWeapon( this, pWeapon ) ) - return; // can't drop the item they asked for, may be our last item or something we can't holster - - UTIL_MakeVectors ( pev->angles ); - - pev->weapons &= ~(1<m_iId);// take item off hud - - CWeaponBox *pWeaponBox = (CWeaponBox *)CBaseEntity::Create( "weaponbox", pev->origin + gpGlobals->v_forward * 10, pev->angles, edict() ); - pWeaponBox->pev->angles.x = 0; - pWeaponBox->pev->angles.z = 0; - pWeaponBox->PackWeapon( pWeapon ); - pWeaponBox->pev->velocity = gpGlobals->v_forward * 300 + gpGlobals->v_forward * 100; - - // drop half of the ammo for this weapon. - int iAmmoIndex; - - iAmmoIndex = GetAmmoIndex ( pWeapon->pszAmmo1() ); // ??? - - if ( iAmmoIndex != -1 ) - { - // this weapon weapon uses ammo, so pack an appropriate amount. - if ( pWeapon->iFlags() & ITEM_FLAG_EXHAUSTIBLE ) - { - // pack up all the ammo, this weapon is its own ammo type - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] ); - m_rgAmmo[ iAmmoIndex ] = 0; - - } - else - { - // pack half of the ammo - pWeaponBox->PackAmmo( MAKE_STRING(pWeapon->pszAmmo1()), m_rgAmmo[ iAmmoIndex ] / 2 ); - m_rgAmmo[ iAmmoIndex ] /= 2; - } - - } - - return;// we're done, so stop searching with the FOR loop. - } - } -} - -//========================================================= -// HasPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// HasNamedPlayerItem Does the player already have this item? -//========================================================= -BOOL CBasePlayer::HasNamedPlayerItem( const char *pszItemName ) -{ - CBasePlayerItem *pItem; - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pItem = m_rgpPlayerItems[ i ]; - - while (pItem) - { - if ( !strcmp( pszItemName, STRING( pItem->pev->classname ) ) ) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - } - - return FALSE; -} - -//========================================================= -// -//========================================================= -BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) -{ - if ( !pWeapon->CanDeploy() ) - { - return FALSE; - } - - ResetAutoaim( ); - - if (m_pActiveItem) - { - m_pActiveItem->Holster( ); - } - - m_pActiveItem = pWeapon; - pWeapon->Deploy( ); - - return TRUE; -} - -//========================================================= -// Dead HEV suit prop -//========================================================= -class CDeadHEV : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_MILITARY; } - - void KeyValue( KeyValueData *pkvd ); - - int m_iPose;// which sequence to display -- temporary, don't need to save - static const char *m_szPoses[4]; -}; - -const char *CDeadHEV::m_szPoses[] = { "deadback", "deadsitting", "deadstomach", "deadtable" }; - -void CDeadHEV::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - -LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CDeadHEV ); - -//========================================================= -// ********** DeadHEV SPAWN ********** -//========================================================= -void CDeadHEV :: Spawn( void ) -{ - PRECACHE_MODEL("models/player.mdl"); - SET_MODEL(ENT(pev), "models/player.mdl"); - - pev->effects = 0; - pev->yaw_speed = 8; - pev->sequence = 0; - pev->body = 1; - m_bloodColor = BLOOD_COLOR_RED; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead hevsuit with bad pose\n" ); - pev->sequence = 0; - pev->effects = EF_BRIGHTFIELD; - } - - // Corpses have less health - pev->health = 8; - - MonsterInitDead(); -} - - -class CStripWeapons : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -private: -}; - -LINK_ENTITY_TO_CLASS( player_weaponstrip, CStripWeapons ); - -void CStripWeapons :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBasePlayer *pPlayer = NULL; - - if ( pActivator && pActivator->IsPlayer() ) - { - pPlayer = (CBasePlayer *)pActivator; - } - else if ( !g_pGameRules->IsDeathmatch() ) - { - pPlayer = (CBasePlayer *)CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - } - - if ( pPlayer ) - pPlayer->RemoveAllItems( FALSE ); -} - - -class CRevertSaved : public CPointEntity -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT MessageThink( void ); - void EXPORT LoadThink( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - inline float Duration( void ) { return pev->dmg_take; } - inline float HoldTime( void ) { return pev->dmg_save; } - inline float MessageTime( void ) { return m_messageTime; } - inline float LoadTime( void ) { return m_loadTime; } - - inline void SetDuration( float duration ) { pev->dmg_take = duration; } - inline void SetHoldTime( float hold ) { pev->dmg_save = hold; } - inline void SetMessageTime( float time ) { m_messageTime = time; } - inline void SetLoadTime( float time ) { m_loadTime = time; } - -private: - float m_messageTime; - float m_loadTime; -}; - -LINK_ENTITY_TO_CLASS( player_loadsaved, CRevertSaved ); - -TYPEDESCRIPTION CRevertSaved::m_SaveData[] = -{ - DEFINE_FIELD( CRevertSaved, m_messageTime, FIELD_FLOAT ), // These are not actual times, but durations, so save as floats - DEFINE_FIELD( CRevertSaved, m_loadTime, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CRevertSaved, CPointEntity ); - -void CRevertSaved :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "duration")) - { - SetDuration( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "holdtime")) - { - SetHoldTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "messagetime")) - { - SetMessageTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "loadtime")) - { - SetLoadTime( atof(pkvd->szValue) ); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CRevertSaved :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - UTIL_ScreenFadeAll( pev->rendercolor, Duration(), HoldTime(), static_cast(pev->renderamt), FFADE_OUT ); - pev->nextthink = gpGlobals->time + MessageTime(); - SetThink( &CRevertSaved::MessageThink ); -} - - -void CRevertSaved :: MessageThink( void ) -{ - UTIL_ShowMessageAll( STRING(pev->message) ); - float nextThink = LoadTime() - MessageTime(); - if ( nextThink > 0 ) - { - pev->nextthink = gpGlobals->time + nextThink; - SetThink( &CRevertSaved::LoadThink ); - } - else - LoadThink(); -} - - -void CRevertSaved :: LoadThink( void ) -{ - if ( !gpGlobals->deathmatch ) - { - SERVER_COMMAND("reload\n"); - } -} - - -//========================================================= -// Multiplayer intermission spots. -//========================================================= -class CInfoIntermission:public CPointEntity -{ - void Spawn( void ); - void Think( void ); -}; - -void CInfoIntermission::Spawn( void ) -{ - UTIL_SetOrigin( pev, pev->origin ); - pev->solid = SOLID_NOT; - pev->effects = EF_NODRAW; - pev->v_angle = g_vecZero; - - pev->nextthink = gpGlobals->time + 2;// let targets spawn! - -} - -void CInfoIntermission::Think ( void ) -{ - edict_t *pTarget; - - // find my target - pTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(pev->target) ); - - if ( !FNullEnt(pTarget) ) - { - pev->v_angle = UTIL_VecToAngles( (pTarget->v.origin - pev->origin).Normalize() ); - pev->v_angle.x = -pev->v_angle.x; - } -} - -LINK_ENTITY_TO_CLASS( info_intermission, CInfoIntermission ); - diff --git a/sdk/dlls/player.h b/sdk/dlls/player.h deleted file mode 100644 index aa13b2a..0000000 --- a/sdk/dlls/player.h +++ /dev/null @@ -1,337 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PLAYER_H -#define PLAYER_H - - -#include "pm_materials.h" - - -#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -// -// Player PHYSICS FLAGS bits -// -#define PFLAG_ONLADDER ( 1<<0 ) -#define PFLAG_ONSWING ( 1<<0 ) -#define PFLAG_ONTRAIN ( 1<<1 ) -#define PFLAG_ONBARNACLE ( 1<<2 ) -#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet -#define PFLAG_USING ( 1<<4 ) // Using a continuous entity -#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. - -// -// generic player -// -//----------------------------------------------------- -//This is Half-Life player entity -//----------------------------------------------------- -#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time - -#define SUIT_GROUP TRUE -#define SUIT_SENTENCE FALSE - -#define SUIT_REPEAT_OK 0 -#define SUIT_NEXT_IN_30SEC 30 -#define SUIT_NEXT_IN_1MIN 60 -#define SUIT_NEXT_IN_5MIN 300 -#define SUIT_NEXT_IN_10MIN 600 -#define SUIT_NEXT_IN_30MIN 1800 -#define SUIT_NEXT_IN_1HOUR 3600 - -#define CSUITNOREPEAT 32 - -#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" -#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" - -#define TEAM_NAME_LENGTH 16 - -typedef enum -{ - PLAYER_IDLE, - PLAYER_WALK, - PLAYER_JUMP, - PLAYER_SUPERJUMP, - PLAYER_DIE, - PLAYER_ATTACK1, -} PLAYER_ANIM; - -#define MAX_ID_RANGE 2048 -#define SBAR_STRING_SIZE 128 - -enum sbar_data -{ - SBAR_ID_TARGETNAME = 1, - SBAR_ID_TARGETHEALTH, - SBAR_ID_TARGETARMOR, - SBAR_END, -}; - -#define CHAT_INTERVAL 1.0f - -class CBasePlayer : public CBaseMonster -{ -public: - - // Spectator camera - void Observer_FindNextPlayer( bool bReverse ); - void Observer_HandleButtons(); - void Observer_SetMode( int iMode ); - void Observer_CheckTarget(); - void Observer_CheckProperties(); - EHANDLE m_hObserverTarget; - float m_flNextObserverInput; - int m_iObserverWeapon; // weapon of current tracked target - int m_iObserverLastMode;// last used observer mode - int IsObserver() { return pev->iuser1; }; - - int random_seed; // See that is shared between client & server for shared weapons code - - int m_iPlayerSound;// the index of the sound list slot reserved for this player - int m_iTargetVolume;// ideal sound volume. - int m_iWeaponVolume;// how loud the player's weapon is right now. - int m_iExtraSoundTypes;// additional classification for this weapon's sound - int m_iWeaponFlash;// brightness of the weapon flash - float m_flStopExtraSoundTime; - - float m_flFlashLightTime; // Time until next battery draw/Recharge - int m_iFlashBattery; // Flashlight Battery Draw - - int m_afButtonLast; - int m_afButtonPressed; - int m_afButtonReleased; - - edict_t *m_pentSndLast; // last sound entity to modify player room type - float m_flSndRoomtype; // last roomtype set by sound entity - float m_flSndRange; // dist from player to sound entity - - float m_flFallVelocity; - - int m_rgItems[MAX_ITEMS]; - int m_fKnownItem; // True when a new item needs to be added - int m_fNewAmmo; // True when a new item has been added - - unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden - float m_fNextSuicideTime; // the time after which the player can next use the suicide command - - -// these are time-sensitive things that we keep track of - float m_flTimeStepSound; // when the last stepping sound was made - float m_flTimeWeaponIdle; // when to play another weapon idle animation. - float m_flSwimTime; // how long player has been underwater - float m_flDuckTime; // how long we've been ducking - float m_flWallJumpTime; // how long until next walljump - - float m_flSuitUpdate; // when to play next suit update - int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update - int m_iSuitPlayNext; // next sentence slot for queue storage; - int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list - float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat - int m_lastDamageAmount; // Last damage taken - float m_tbdPrev; // Time-based damage timer - - float m_flgeigerRange; // range to nearest radiation source - float m_flgeigerDelay; // delay per update of range msg to client - int m_igeigerRangePrev; - int m_iStepLeft; // alternate left/right foot stepping sound - char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on - char m_chTextureType; // current texture type - - int m_idrowndmg; // track drowning damage taken - int m_idrownrestored; // track drowning damage restored - - int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to - // the hude via the DAMAGE message - BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent - BOOL m_fGameHUDInitialized; - int m_iTrain; // Train control position - BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info - - EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank - float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) - - BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. - BOOL m_fLongJump; // does this player have the longjump module? - - float m_tSneaking; - int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages - int m_iClientHealth; // the health currently known by the client. If this changes, send a new - int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new - int m_iHideHUD; // the players hud weapon info is to be hidden - int m_iClientHideHUD; - int m_iFOV; // field of view - int m_iClientFOV; // client's known FOV - // usable player items - CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; - CBasePlayerItem *m_pActiveItem; - CBasePlayerItem *m_pClientActiveItem; // client version of the active item - CBasePlayerItem *m_pLastItem; - // shared ammo slots - int m_rgAmmo[MAX_AMMO_SLOTS]; - int m_rgAmmoLast[MAX_AMMO_SLOTS]; - - Vector m_vecAutoAim; - BOOL m_fOnTarget; - int m_iDeaths; - float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn - - int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE - - int m_nCustomSprayFrames;// Custom clan logo frames for this player - float m_flNextDecalTime;// next time this player can spray a decal - - char m_szTeamName[TEAM_NAME_LENGTH]; - - virtual void Spawn( void ); - void Pain( void ); - -// virtual void Think( void ); - virtual void Jump( void ); - virtual void Duck( void ); - virtual void PreThink( void ); - virtual void PostThink( void ); - virtual Vector GetGunPosition( void ); - virtual int TakeHealth( float flHealth, int bitsDamageType ); - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual void Killed( entvars_t *pevAttacker, int iGib ); - virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at - virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } - virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } - virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } - virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } - virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } - virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned - - virtual BOOL IsNetClient( void ) { return TRUE; } // Bots should return FALSE for this, they can't receive NET messages - // Spectators should return TRUE for this - virtual const char *TeamID( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - void RenewItems(void); - void PackDeadPlayerItems( void ); - void RemoveAllItems( BOOL removeSuit ); - BOOL SwitchWeapon( CBasePlayerItem *pWeapon ); - - // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) - virtual void UpdateClientData( void ); - - static TYPEDESCRIPTION m_playerSaveData[]; - - // Player is moved across the transition by other means - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual void Precache( void ); - BOOL IsOnLadder( void ); - BOOL FlashlightIsOn( void ); - void FlashlightTurnOn( void ); - void FlashlightTurnOff( void ); - - void UpdatePlayerSound ( void ); - void DeathSound ( void ); - - int Classify ( void ); - void SetAnimation( PLAYER_ANIM playerAnim ); - void SetWeaponAnimType( const char *szExtention ); - char m_szAnimExtention[32]; - - // custom player functions - virtual void ImpulseCommands( void ); - void CheatImpulseCommands( int iImpulse ); - - void StartDeathCam( void ); - void StartObserver( Vector vecPosition, Vector vecViewAngle ); - - void AddPoints( int score, BOOL bAllowNegativeScore ); - void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); - BOOL AddPlayerItem( CBasePlayerItem *pItem ); - BOOL RemovePlayerItem( CBasePlayerItem *pItem ); - void DropPlayerItem ( char *pszItemName ); - BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); - BOOL HasNamedPlayerItem( const char *pszItemName ); - BOOL HasWeapons( void );// do I have ANY weapons? - void SelectPrevItem( int iItem ); - void SelectNextItem( int iItem ); - void SelectLastItem(void); - void SelectItem(const char *pstr); - void ItemPreFrame( void ); - void ItemPostFrame( void ); - void GiveNamedItem( const char *szName ); - void EnableControl(BOOL fControl); - - int GiveAmmo( int iAmount, const char *szName, int iMax ); - void SendAmmoUpdate(void); - - void WaterMove( void ); - void EXPORT PlayerDeathThink( void ); - void PlayerUse( void ); - - void CheckSuitUpdate(); - void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat); - void UpdateGeigerCounter( void ); - void CheckTimeBasedDamage( void ); - - BOOL FBecomeProne ( void ); - void BarnacleVictimBitten ( entvars_t *pevBarnacle ); - void BarnacleVictimReleased ( void ); - static int GetAmmoIndex(const char *psz); - int AmmoInventory( int iAmmoIndex ); - int Illumination( void ); - - void ResetAutoaim( void ); - Vector GetAutoaimVector( float flDelta ); - Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); - - void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. - - void DeathMessage( entvars_t *pevKiller ); - - void SetCustomDecalFrames( int nFrames ); - int GetCustomDecalFrames( void ); - - void TabulateAmmo( void ); - - float m_flStartCharge; - float m_flAmmoStartCharge; - float m_flPlayAftershock; - float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? - - //Player ID - void InitStatusBar( void ); - void UpdateStatusBar( void ); - int m_izSBarState[ SBAR_END ]; - float m_flNextSBarUpdateTime; - float m_flStatusBarDisappearDelay; - char m_SbarString0[ SBAR_STRING_SIZE ]; - char m_SbarString1[ SBAR_STRING_SIZE ]; - - float m_flNextChatTime; - -}; - -#define AUTOAIM_2DEGREES 0.0348994967025 -#define AUTOAIM_5DEGREES 0.08715574274766 -#define AUTOAIM_8DEGREES 0.1391731009601 -#define AUTOAIM_10DEGREES 0.1736481776669 - - -extern int gmsgHudText; -extern BOOL gInitHUD; - -#endif // PLAYER_H diff --git a/sdk/dlls/playermonster.cpp b/sdk/dlls/playermonster.cpp deleted file mode 100644 index 798c25d..0000000 --- a/sdk/dlls/playermonster.cpp +++ /dev/null @@ -1,122 +0,0 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -//========================================================= -// playermonster - for scripted sequence use. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -// For holograms, make them not solid so the player can walk through them -#define SF_MONSTERPLAYER_NOTSOLID 4 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CPlayerMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int ISoundMask ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_player, CPlayerMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CPlayerMonster :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CPlayerMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// ISoundMask - player monster can't hear. -//========================================================= -int CPlayerMonster :: ISoundMask ( void ) -{ - return NULL; -} - -//========================================================= -// Spawn -//========================================================= -void CPlayerMonster :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/player.mdl"); - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - - MonsterInit(); - if ( pev->spawnflags & SF_MONSTERPLAYER_NOTSOLID ) - { - pev->solid = SOLID_NOT; - pev->takedamage = DAMAGE_NO; - } -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CPlayerMonster :: Precache() -{ - PRECACHE_MODEL("models/player.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/sdk/dlls/python.cpp b/sdk/dlls/python.cpp deleted file mode 100644 index f8762f1..0000000 --- a/sdk/dlls/python.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "monsters.h" -#include "player.h" -#include "gamerules.h" - - -enum python_e { - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -LINK_ENTITY_TO_CLASS( weapon_python, CPython ); -LINK_ENTITY_TO_CLASS( weapon_357, CPython ); - -int CPython::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "357"; - p->iMaxAmmo1 = _357_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = PYTHON_MAX_CLIP; - p->iFlags = 0; - p->iSlot = 1; - p->iPosition = 1; - p->iId = m_iId = WEAPON_PYTHON; - p->iWeight = PYTHON_WEIGHT; - - return 1; -} - -int CPython::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -void CPython::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_357"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_PYTHON; - SET_MODEL(ENT(pev), "models/w_357.mdl"); - - m_iDefaultAmmo = PYTHON_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CPython::Precache( void ) -{ - PRECACHE_MODEL("models/v_357.mdl"); - PRECACHE_MODEL("models/w_357.mdl"); - PRECACHE_MODEL("models/p_357.mdl"); - - PRECACHE_MODEL("models/w_357ammobox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND ("weapons/357_reload1.wav"); - PRECACHE_SOUND ("weapons/357_cock1.wav"); - PRECACHE_SOUND ("weapons/357_shot1.wav"); - PRECACHE_SOUND ("weapons/357_shot2.wav"); - - m_usFirePython = PRECACHE_EVENT( 1, "events/python.sc" ); -} - -BOOL CPython::Deploy( ) -{ -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // enable laser sight geometry. - pev->body = 1; - } - else - { - pev->body = 0; - } - - return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", UseDecrement(), pev->body ); -} - - -void CPython::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - if ( m_fInZoom ) - { - SecondaryAttack(); - } - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - SendWeaponAnim( PYTHON_HOLSTER ); -} - -void CPython::SecondaryAttack( void ) -{ -#ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) -#else - if ( !g_pGameRules->IsMultiplayer() ) -#endif - { - return; - } - - if ( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - else if ( m_pPlayer->pev->fov != 40 ) - { - m_fInZoom = TRUE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; - } - - m_flNextSecondaryAttack = 0.5; -} - -void CPython::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = 0.15; - return; - } - - if (m_iClip <= 0) - { - if (!m_fFireOnEmpty) - Reload( ); - else - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_flNextPrimaryAttack = 0.15; - } - - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFirePython, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flNextPrimaryAttack = 0.75; - m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CPython::Reload( void ) -{ - if ( m_pPlayer->ammo_357 <= 0 ) - return; - - if ( m_pPlayer->pev->fov != 0 ) - { - m_fInZoom = FALSE; - m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - - DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope ); -} - - -void CPython::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.5) - { - iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = (70.0/30.0); - } - else if (flRand <= 0.7) - { - iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = (60.0/30.0); - } - else if (flRand <= 0.9) - { - iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = (88.0/30.0); - } - else - { - iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = (170.0/30.0); - } - - int bUseScope = FALSE; -#ifdef CLIENT_DLL - bUseScope = bIsMultiplayer(); -#else - bUseScope = g_pGameRules->IsMultiplayer(); -#endif - - SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); -} - - -class CPythonAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_357ammobox.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_357ammobox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_357BOX_GIVE, "357", _357_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_357, CPythonAmmo ); - - -#endif diff --git a/sdk/dlls/rat.cpp b/sdk/dlls/rat.cpp deleted file mode 100644 index ba858eb..0000000 --- a/sdk/dlls/rat.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// rat - environmental monster -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CRat : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); -}; -LINK_ENTITY_TO_CLASS( monster_rat, CRat ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRat :: Classify ( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRat :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 45; - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRat :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/bigrat.mdl"); - UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = 8; - pev->view_ofs = Vector ( 0, 0, 6 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRat :: Precache() -{ - PRECACHE_MODEL("models/bigrat.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= diff --git a/sdk/dlls/roach.cpp b/sdk/dlls/roach.cpp deleted file mode 100644 index 6a0aca9..0000000 --- a/sdk/dlls/roach.cpp +++ /dev/null @@ -1,460 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// cockroach -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "soundent.h" -#include "decals.h" - -#define ROACH_IDLE 0 -#define ROACH_BORED 1 -#define ROACH_SCARED_BY_ENT 2 -#define ROACH_SCARED_BY_LIGHT 3 -#define ROACH_SMELL_FOOD 4 -#define ROACH_EAT 5 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -class CRoach : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - void EXPORT MonsterThink ( void ); - void Move ( float flInterval ); - void PickNewDest ( int iCondition ); - void EXPORT Touch ( CBaseEntity *pOther ); - void Killed( entvars_t *pevAttacker, int iGib ); - - float m_flLastLightLevel; - float m_flNextSmellTime; - int Classify ( void ); - void Look ( int iDistance ); - int ISoundMask ( void ); - - // UNDONE: These don't necessarily need to be save/restored, but if we add more data, it may - BOOL m_fLightHacked; - int m_iMode; - // ----------------------------- -}; -LINK_ENTITY_TO_CLASS( monster_cockroach, CRoach ); - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CRoach :: ISoundMask ( void ) -{ - return bits_SOUND_CARCASS | bits_SOUND_MEAT; -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CRoach :: Classify ( void ) -{ - return CLASS_INSECT; -} - -//========================================================= -// Touch -//========================================================= -void CRoach :: Touch ( CBaseEntity *pOther ) -{ - Vector vecSpot; - TraceResult tr; - - if ( pOther->pev->velocity == g_vecZero || !pOther->IsPlayer() ) - { - return; - } - - vecSpot = pev->origin + Vector ( 0 , 0 , 8 );//move up a bit, and trace down. - UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -24 ), ignore_monsters, ENT(pev), & tr); - - // This isn't really blood. So you don't have to screen it out based on violence levels (UTIL_ShouldShowBlood()) - UTIL_DecalTrace( &tr, DECAL_YBLOOD1 +RANDOM_LONG(0,5) ); - - TakeDamage( pOther->pev, pOther->pev, pev->health, DMG_CRUSH ); -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CRoach :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - - pev->yaw_speed = ys; -} - -//========================================================= -// Spawn -//========================================================= -void CRoach :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/roach.mdl"); - UTIL_SetSize( pev, Vector( -1, -1, 0 ), Vector( 1, 1, 2 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_YELLOW; - pev->effects = 0; - pev->health = 1; - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); - SetActivity ( ACT_IDLE ); - - pev->view_ofs = Vector ( 0, 0, 1 );// position of the eyes relative to monster's origin. - pev->takedamage = DAMAGE_YES; - m_fLightHacked = FALSE; - m_flLastLightLevel = -1; - m_iMode = ROACH_IDLE; - m_flNextSmellTime = gpGlobals->time; -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CRoach :: Precache() -{ - PRECACHE_MODEL("models/roach.mdl"); - - PRECACHE_SOUND("roach/rch_die.wav"); - PRECACHE_SOUND("roach/rch_walk.wav"); - PRECACHE_SOUND("roach/rch_smash.wav"); -} - - -//========================================================= -// Killed. -//========================================================= -void CRoach :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->solid = SOLID_NOT; - - //random sound - if ( RANDOM_LONG(0,4) == 1 ) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "roach/rch_die.wav", 0.8, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } - else - { - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_smash.wav", 0.7, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } - - CSoundEnt::InsertSound ( bits_SOUND_WORLD, pev->origin, 128, 1 ); - - CBaseEntity *pOwner = CBaseEntity::Instance(pev->owner); - if ( pOwner ) - { - pOwner->DeathNotice( pev ); - } - UTIL_Remove( this ); -} - -//========================================================= -// MonsterThink, overridden for roaches. -//========================================================= -void CRoach :: MonsterThink( void ) -{ - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(1,1.5); - else - pev->nextthink = gpGlobals->time + 0.1;// keep monster thinking - - float flInterval = StudioFrameAdvance( ); // animate - - if ( !m_fLightHacked ) - { - // if light value hasn't been collection for the first time yet, - // suspend the creature for a second so the world finishes spawning, then we'll collect the light level. - pev->nextthink = gpGlobals->time + 1; - m_fLightHacked = TRUE; - return; - } - else if ( m_flLastLightLevel < 0 ) - { - // collect light level for the first time, now that all of the lightmaps in the roach's area have been calculated. - m_flLastLightLevel = GETENTITYILLUM( ENT( pev ) ); - } - - switch ( m_iMode ) - { - case ROACH_IDLE: - case ROACH_EAT: - { - // if not moving, sample environment to see if anything scary is around. Do a radius search 'look' at random. - if ( RANDOM_LONG(0,3) == 1 ) - { - Look( 150 ); - if (HasConditions(bits_COND_SEE_FEAR)) - { - // if see something scary - //ALERT ( at_aiconsole, "Scared\n" ); - Eat( 30 + ( RANDOM_LONG(0,14) ) );// roach will ignore food for 30 to 45 seconds - PickNewDest( ROACH_SCARED_BY_ENT ); - SetActivity ( ACT_WALK ); - } - else if ( RANDOM_LONG(0,149) == 1 ) - { - // if roach doesn't see anything, there's still a chance that it will move. (boredom) - //ALERT ( at_aiconsole, "Bored\n" ); - PickNewDest( ROACH_BORED ); - SetActivity ( ACT_WALK ); - - if ( m_iMode == ROACH_EAT ) - { - // roach will ignore food for 30 to 45 seconds if it got bored while eating. - Eat( 30 + ( RANDOM_LONG(0,14) ) ); - } - } - } - - // don't do this stuff if eating! - if ( m_iMode == ROACH_IDLE ) - { - if ( FShouldEat() ) - { - Listen(); - } - - if ( GETENTITYILLUM( ENT(pev) ) > m_flLastLightLevel ) - { - // someone turned on lights! - //ALERT ( at_console, "Lights!\n" ); - PickNewDest( ROACH_SCARED_BY_LIGHT ); - SetActivity ( ACT_WALK ); - } - else if ( HasConditions(bits_COND_SMELL_FOOD) ) - { - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - // roach smells food and is just standing around. Go to food unless food isn't on same z-plane. - if ( pSound && abs( pSound->m_vecOrigin.z - pev->origin.z ) <= 3 ) - { - PickNewDest( ROACH_SMELL_FOOD ); - SetActivity ( ACT_WALK ); - } - } - } - - break; - } - case ROACH_SCARED_BY_LIGHT: - { - // if roach was scared by light, then stop if we're over a spot at least as dark as where we started! - if ( GETENTITYILLUM( ENT( pev ) ) <= m_flLastLightLevel ) - { - SetActivity ( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// make this our new light level. - } - break; - } - } - - if ( m_flGroundSpeed != 0 ) - { - Move( flInterval ); - } -} - -//========================================================= -// Picks a new spot for roach to run to.( -//========================================================= -void CRoach :: PickNewDest ( int iCondition ) -{ - Vector vecNewDir; - Vector vecDest; - float flDist; - - m_iMode = iCondition; - - if ( m_iMode == ROACH_SMELL_FOOD ) - { - // find the food and go there. - CSound *pSound; - - pSound = CSoundEnt::SoundPointerForIndex( m_iAudibleList ); - - if ( pSound ) - { - m_Route[ 0 ].vecLocation.x = pSound->m_vecOrigin.x + ( 3 - RANDOM_LONG(0,5) ); - m_Route[ 0 ].vecLocation.y = pSound->m_vecOrigin.y + ( 3 - RANDOM_LONG(0,5) ); - m_Route[ 0 ].vecLocation.z = pSound->m_vecOrigin.z; - m_Route[ 0 ].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); - return; - } - } - - do - { - // picks a random spot, requiring that it be at least 128 units away - // else, the roach will pick a spot too close to itself and run in - // circles. this is a hack but buys me time to work on the real monsters. - vecNewDir.x = RANDOM_FLOAT( -1, 1 ); - vecNewDir.y = RANDOM_FLOAT( -1, 1 ); - flDist = 256 + ( RANDOM_LONG(0,255) ); - vecDest = pev->origin + vecNewDir * flDist; - - } while ( ( vecDest - pev->origin ).Length2D() < 128 ); - - m_Route[ 0 ].vecLocation.x = vecDest.x; - m_Route[ 0 ].vecLocation.y = vecDest.y; - m_Route[ 0 ].vecLocation.z = pev->origin.z; - m_Route[ 0 ].iType = bits_MF_TO_LOCATION; - m_movementGoal = RouteClassify( m_Route[ 0 ].iType ); - - if ( RANDOM_LONG(0,9) == 1 ) - { - // every once in a while, a roach will play a skitter sound when they decide to run - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "roach/rch_walk.wav", 1, ATTN_NORM, 0, 80 + RANDOM_LONG(0,39) ); - } -} - -//========================================================= -// roach's move function -//========================================================= -void CRoach :: Move ( float flInterval ) -{ - float flWaypointDist; - Vector vecApex; - - // local move to waypoint. - flWaypointDist = ( m_Route[ m_iRouteIndex ].vecLocation - pev->origin ).Length2D(); - MakeIdealYaw ( m_Route[ m_iRouteIndex ].vecLocation ); - - ChangeYaw ( pev->yaw_speed ); - UTIL_MakeVectors( pev->angles ); - - if ( RANDOM_LONG(0,7) == 1 ) - { - // randomly check for blocked path.(more random load balancing) - if ( !WALK_MOVE( ENT(pev), pev->ideal_yaw, 4, WALKMOVE_NORMAL ) ) - { - // stuck, so just pick a new spot to run off to - PickNewDest( m_iMode ); - } - } - - WALK_MOVE( ENT(pev), pev->ideal_yaw, m_flGroundSpeed * flInterval, WALKMOVE_NORMAL ); - - // if the waypoint is closer than step size, then stop after next step (ok for roach to overshoot) - if ( flWaypointDist <= m_flGroundSpeed * flInterval ) - { - // take truncated step and stop - - SetActivity ( ACT_IDLE ); - m_flLastLightLevel = GETENTITYILLUM( ENT ( pev ) );// this is roach's new comfortable light level - - if ( m_iMode == ROACH_SMELL_FOOD ) - { - m_iMode = ROACH_EAT; - } - else - { - m_iMode = ROACH_IDLE; - } - } - - if ( RANDOM_LONG(0,149) == 1 && m_iMode != ROACH_SCARED_BY_LIGHT && m_iMode != ROACH_SMELL_FOOD ) - { - // random skitter while moving as long as not on a b-line to get out of light or going to food - PickNewDest( FALSE ); - } -} - -//========================================================= -// Look - overriden for the roach, which can virtually see -// 360 degrees. -//========================================================= -void CRoach :: Look ( int iDistance ) -{ - CBaseEntity *pSightEnt = NULL;// the current visible entity that we're dealing with - CBaseEntity *pPreviousEnt;// the last entity added to the link list - int iSighted = 0; - - // DON'T let visibility information from last frame sit around! - ClearConditions( bits_COND_SEE_HATE |bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR ); - - // don't let monsters outside of the player's PVS act up, or most of the interesting - // things will happen before the player gets there! - if ( FNullEnt( FIND_CLIENT_IN_PVS( edict() ) ) ) - { - return; - } - - m_pLink = NULL; - pPreviousEnt = this; - - // Does sphere also limit itself to PVS? - // Examine all entities within a reasonable radius - // !!!PERFORMANCE - let's trivially reject the ent list before radius searching! - while ((pSightEnt = UTIL_FindEntityInSphere( pSightEnt, pev->origin, iDistance )) != NULL) - { - // only consider ents that can be damaged. !!!temporarily only considering other monsters and clients - if ( pSightEnt->IsPlayer() || FBitSet ( pSightEnt->pev->flags, FL_MONSTER ) ) - { - if ( /*FVisible( pSightEnt ) &&*/ !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && pSightEnt->pev->health > 0 ) - { - // NULL the Link pointer for each ent added to the link list. If other ents follow, the will overwrite - // this value. If this ent happens to be the last, the list will be properly terminated. - pPreviousEnt->m_pLink = pSightEnt; - pSightEnt->m_pLink = NULL; - pPreviousEnt = pSightEnt; - - // don't add the Enemy's relationship to the conditions. We only want to worry about conditions when - // we see monsters other than the Enemy. - switch ( IRelationship ( pSightEnt ) ) - { - case R_FR: - iSighted |= bits_COND_SEE_FEAR; - break; - case R_NO: - break; - default: - ALERT ( at_console, "%s can't asses %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) ); - break; - } - } - } - } - SetConditions( iSighted ); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - diff --git a/sdk/dlls/rpg.cpp b/sdk/dlls/rpg.cpp deleted file mode 100644 index 1e99c45..0000000 --- a/sdk/dlls/rpg.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - - - - -enum rpg_e { - RPG_IDLE = 0, - RPG_FIDGET, - RPG_RELOAD, // to reload - RPG_FIRE2, // to empty - RPG_HOLSTER1, // loaded - RPG_DRAW1, // loaded - RPG_HOLSTER2, // unloaded - RPG_DRAW_UL, // unloaded - RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget -}; - -LINK_ENTITY_TO_CLASS( weapon_rpg, CRpg ); - -#ifndef CLIENT_DLL - -LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); - -//========================================================= -//========================================================= -CLaserSpot *CLaserSpot::CreateSpot( void ) -{ - CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); - pSpot->Spawn(); - - pSpot->pev->classname = MAKE_STRING("laser_spot"); - - return pSpot; -} - -//========================================================= -//========================================================= -void CLaserSpot::Spawn( void ) -{ - Precache( ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_NOT; - - pev->rendermode = kRenderGlow; - pev->renderfx = kRenderFxNoDissipation; - pev->renderamt = 255; - - SET_MODEL(ENT(pev), "sprites/laserdot.spr"); - UTIL_SetOrigin( pev, pev->origin ); -}; - -//========================================================= -// Suspend- make the laser sight invisible. -//========================================================= -void CLaserSpot::Suspend( float flSuspendTime ) -{ - pev->effects |= EF_NODRAW; - - SetThink( &CLaserSpot::Revive ); - pev->nextthink = gpGlobals->time + flSuspendTime; -} - -//========================================================= -// Revive - bring a suspended laser sight back. -//========================================================= -void CLaserSpot::Revive( void ) -{ - pev->effects &= ~EF_NODRAW; - - SetThink( NULL ); -} - -void CLaserSpot::Precache( void ) -{ - PRECACHE_MODEL("sprites/laserdot.spr"); -}; - -LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket ); - -//========================================================= -//========================================================= -CRpgRocket *CRpgRocket::CreateRpgRocket( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CRpg *pLauncher ) -{ - CRpgRocket *pRocket = GetClassPtr( (CRpgRocket *)NULL ); - - UTIL_SetOrigin( pRocket->pev, vecOrigin ); - pRocket->pev->angles = vecAngles; - pRocket->Spawn(); - pRocket->SetTouch( &CRpgRocket::RocketTouch ); - pRocket->m_pLauncher = pLauncher;// remember what RPG fired me. - pRocket->m_pLauncher->m_cActiveRockets++;// register this missile as active for the launcher - pRocket->pev->owner = pOwner->edict(); - - return pRocket; -} - -//========================================================= -//========================================================= -void CRpgRocket :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/rpgrocket.mdl"); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin( pev, pev->origin ); - - pev->classname = MAKE_STRING("rpg_rocket"); - - SetThink( &CRpgRocket::IgniteThink ); - SetTouch( &CRpgRocket::ExplodeTouch ); - - pev->angles.x -= 30; - UTIL_MakeVectors( pev->angles ); - pev->angles.x = -(pev->angles.x + 30); - - pev->velocity = gpGlobals->v_forward * 250; - pev->gravity = 0.5; - - pev->nextthink = gpGlobals->time + 0.4; - - pev->dmg = gSkillData.plrDmgRPG; -} - -//========================================================= -//========================================================= -void CRpgRocket :: RocketTouch ( CBaseEntity *pOther ) -{ - if ( m_pLauncher ) - { - // my launcher is still around, tell it I'm dead. - m_pLauncher->m_cActiveRockets--; - } - - STOP_SOUND( edict(), CHAN_VOICE, "weapons/rocket1.wav" ); - ExplodeTouch( pOther ); -} - -//========================================================= -//========================================================= -void CRpgRocket :: Precache( void ) -{ - PRECACHE_MODEL("models/rpgrocket.mdl"); - m_iTrail = PRECACHE_MODEL("sprites/smoke.spr"); - PRECACHE_SOUND ("weapons/rocket1.wav"); -} - - -void CRpgRocket :: IgniteThink( void ) -{ - // pev->movetype = MOVETYPE_TOSS; - - pev->movetype = MOVETYPE_FLY; - pev->effects |= EF_LIGHT; - - // make rocket sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav", 1, 0.5 ); - - // rocket trail - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - - WRITE_BYTE( TE_BEAMFOLLOW ); - WRITE_SHORT(entindex()); // entity - WRITE_SHORT(m_iTrail ); // model - WRITE_BYTE( 40 ); // life - WRITE_BYTE( 5 ); // width - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 224 ); // r, g, b - WRITE_BYTE( 255 ); // r, g, b - WRITE_BYTE( 255 ); // brightness - - MESSAGE_END(); // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS) - - m_flIgniteTime = gpGlobals->time; - - // set to follow laser spot - SetThink( &CRpgRocket::FollowThink ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CRpgRocket :: FollowThink( void ) -{ - CBaseEntity *pOther = NULL; - Vector vecTarget; - Vector vecDir; - float flDist, flMax, flDot; - TraceResult tr; - - UTIL_MakeAimVectors( pev->angles ); - - vecTarget = gpGlobals->v_forward; - flMax = 4096; - - // Examine all entities within a reasonable radius - while ((pOther = UTIL_FindEntityByClassname( pOther, "laser_spot" )) != NULL) - { - UTIL_TraceLine ( pev->origin, pOther->pev->origin, dont_ignore_monsters, ENT(pev), &tr ); - // ALERT( at_console, "%f\n", tr.flFraction ); - if (tr.flFraction >= 0.90) - { - vecDir = pOther->pev->origin - pev->origin; - flDist = vecDir.Length( ); - vecDir = vecDir.Normalize( ); - flDot = DotProduct( gpGlobals->v_forward, vecDir ); - if ((flDot > 0) && (flDist * (1 - flDot) < flMax)) - { - flMax = flDist * (1 - flDot); - vecTarget = vecDir; - } - } - } - - pev->angles = UTIL_VecToAngles( vecTarget ); - - // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it. - float flSpeed = pev->velocity.Length(); - if (gpGlobals->time - m_flIgniteTime < 1.0) - { - pev->velocity = pev->velocity * 0.2 + vecTarget * (flSpeed * 0.8 + 400); - if (pev->waterlevel == 3) - { - // go slow underwater - if (pev->velocity.Length() > 300) - { - pev->velocity = pev->velocity.Normalize() * 300; - } - UTIL_BubbleTrail( pev->origin - pev->velocity * 0.1, pev->origin, 4 ); - } - else - { - if (pev->velocity.Length() > 2000) - { - pev->velocity = pev->velocity.Normalize() * 2000; - } - } - } - else - { - if (pev->effects & EF_LIGHT) - { - pev->effects = 0; - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/rocket1.wav" ); - } - pev->velocity = pev->velocity * 0.2 + vecTarget * flSpeed * 0.798; - if (pev->waterlevel == 0 && pev->velocity.Length() < 1500) - { - Detonate( ); - } - } - // ALERT( at_console, "%.0f\n", flSpeed ); - - pev->nextthink = gpGlobals->time + 0.1; -} -#endif - - - -void CRpg::Reload( void ) -{ - int iResult = 0; - - if ( m_iClip == 1 ) - { - // don't bother with any of this if don't need to reload. - return; - } - - if ( m_pPlayer->ammo_rockets <= 0 ) - return; - - // because the RPG waits to autoreload when no missiles are active while the LTD is on, the - // weapons code is constantly calling into this function, but is often denied because - // a) missiles are in flight, but the LTD is on - // or - // b) player is totally out of ammo and has nothing to switch to, and should be allowed to - // shine the designator around - // - // Set the next attack time into the future so that WeaponIdle will get called more often - // than reload, allowing the RPG LTD to be updated - - m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - - if ( m_cActiveRockets && m_fSpotActive ) - { - // no reloading when there are active missiles tracking the designator. - // ward off future autoreload attempts by setting next attack time into the future for a bit. - return; - } - -#ifndef CLIENT_DLL - if ( m_pSpot && m_fSpotActive ) - { - m_pSpot->Suspend( 2.1 ); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; - } -#endif - - if ( m_iClip == 0 ) - iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); - - if ( iResult ) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - -} - -void CRpg::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_RPG; - - SET_MODEL(ENT(pev), "models/w_rpg.mdl"); - m_fSpotActive = 1; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // more default ammo in multiplay. - m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; - } - else - { - m_iDefaultAmmo = RPG_DEFAULT_GIVE; - } - - FallInit();// get ready to fall down. -} - - -void CRpg::Precache( void ) -{ - PRECACHE_MODEL("models/w_rpg.mdl"); - PRECACHE_MODEL("models/v_rpg.mdl"); - PRECACHE_MODEL("models/p_rpg.mdl"); - - PRECACHE_SOUND("items/9mmclip1.wav"); - - UTIL_PrecacheOther( "laser_spot" ); - UTIL_PrecacheOther( "rpg_rocket" ); - - PRECACHE_SOUND("weapons/rocketfire1.wav"); - PRECACHE_SOUND("weapons/glauncher.wav"); // alternative fire sound - - m_usRpg = PRECACHE_EVENT ( 1, "events/rpg.sc" ); -} - - -int CRpg::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "rockets"; - p->iMaxAmmo1 = ROCKET_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = RPG_MAX_CLIP; - p->iSlot = 3; - p->iPosition = 0; - p->iId = m_iId = WEAPON_RPG; - p->iFlags = 0; - p->iWeight = RPG_WEIGHT; - - return 1; -} - -int CRpg::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - -BOOL CRpg::Deploy( ) -{ - if ( m_iClip == 0 ) - { - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW_UL, "rpg" ); - } - - return DefaultDeploy( "models/v_rpg.mdl", "models/p_rpg.mdl", RPG_DRAW1, "rpg" ); -} - - -BOOL CRpg::CanHolster( void ) -{ - if ( m_fSpotActive && m_cActiveRockets ) - { - // can't put away while guiding a missile. - return FALSE; - } - - return TRUE; -} - -void CRpg::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE;// cancel any reload in progress. - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - SendWeaponAnim( RPG_HOLSTER1 ); - -#ifndef CLIENT_DLL - if (m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NEVER ); - m_pSpot = NULL; - } -#endif - -} - - - -void CRpg::PrimaryAttack() -{ - if ( m_iClip ) - { - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; - -#ifndef CLIENT_DLL - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_forward * 16 + gpGlobals->v_right * 8 + gpGlobals->v_up * -8; - - CRpgRocket *pRocket = CRpgRocket::CreateRpgRocket( vecSrc, m_pPlayer->pev->v_angle, m_pPlayer, this ); - - UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake. - pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ); -#endif - - // firing RPG no longer turns on the designator. ALT fire is a toggle switch for the LTD. - // Ken signed up for this as a global change (sjb) - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); - - m_iClip--; - - m_flNextPrimaryAttack = GetNextAttackDelay(1.5); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - else - { - PlayEmptySound( ); - } - UpdateSpot( ); -} - - -void CRpg::SecondaryAttack() -{ - m_fSpotActive = ! m_fSpotActive; - -#ifndef CLIENT_DLL - if (!m_fSpotActive && m_pSpot) - { - m_pSpot->Killed( NULL, GIB_NORMAL ); - m_pSpot = NULL; - } -#endif - - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; -} - - -void CRpg::WeaponIdle( void ) -{ - UpdateSpot( ); - - ResetEmptySound( ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75 || m_fSpotActive) - { - if ( m_iClip == 0 ) - iAnim = RPG_IDLE_UL; - else - iAnim = RPG_IDLE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; - } - else - { - if ( m_iClip == 0 ) - iAnim = RPG_FIDGET_UL; - else - iAnim = RPG_FIDGET; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; - } - - SendWeaponAnim( iAnim ); - } - else - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; - } -} - - - -void CRpg::UpdateSpot( void ) -{ - -#ifndef CLIENT_DLL - if (m_fSpotActive) - { - if (!m_pSpot) - { - m_pSpot = CLaserSpot::CreateSpot(); - } - - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( );; - Vector vecAiming = gpGlobals->v_forward; - - TraceResult tr; - UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * 8192, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr ); - - UTIL_SetOrigin( m_pSpot->pev, tr.vecEndPos ); - } -#endif - -} - - -class CRpgAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_rpgammo.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_rpgammo.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - int iGive; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // hand out more ammo per rocket in multiplayer. - iGive = AMMO_RPGCLIP_GIVE * 2; - } - else - { - iGive = AMMO_RPGCLIP_GIVE; - } - - if (pOther->GiveAmmo( iGive, "rockets", ROCKET_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_rpgclip, CRpgAmmo ); - -#endif diff --git a/sdk/dlls/satchel.cpp b/sdk/dlls/satchel.cpp deleted file mode 100644 index e4e673a..0000000 --- a/sdk/dlls/satchel.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -enum satchel_e { - SATCHEL_IDLE1 = 0, - SATCHEL_FIDGET1, - SATCHEL_DRAW, - SATCHEL_DROP -}; - -enum satchel_radio_e { - SATCHEL_RADIO_IDLE1 = 0, - SATCHEL_RADIO_FIDGET1, - SATCHEL_RADIO_DRAW, - SATCHEL_RADIO_FIRE, - SATCHEL_RADIO_HOLSTER -}; - - - -class CSatchelCharge : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - void BounceSound( void ); - - void EXPORT SatchelSlide( CBaseEntity *pOther ); - void EXPORT SatchelThink( void ); - -public: - void Deactivate( void ); -}; -LINK_ENTITY_TO_CLASS( monster_satchel, CSatchelCharge ); - -//========================================================= -// Deactivate - do whatever it is we do to an orphaned -// satchel when we don't want it in the world anymore. -//========================================================= -void CSatchelCharge::Deactivate( void ) -{ - pev->solid = SOLID_NOT; - UTIL_Remove( this ); -} - - -void CSatchelCharge :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_satchel.mdl"); - //UTIL_SetSize(pev, Vector( -16, -16, -4), Vector(16, 16, 32)); // Old box -- size of headcrab monsters/players get blocked by this - UTIL_SetSize(pev, Vector( -4, -4, -4), Vector(4, 4, 4)); // Uses point-sized, and can be stepped over - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSatchelCharge::SatchelSlide ); - SetUse( &CSatchelCharge::DetonateUse ); - SetThink( &CSatchelCharge::SatchelThink ); - pev->nextthink = gpGlobals->time + 0.1; - - pev->gravity = 0.5; - pev->friction = 0.8; - - pev->dmg = gSkillData.plrDmgSatchel; - // ResetSequenceInfo( ); - pev->sequence = 1; -} - - -void CSatchelCharge::SatchelSlide( CBaseEntity *pOther ) -{ - // don't hit the guy that launched this grenade - if ( pOther->edict() == pev->owner ) - return; - - // pev->avelocity = Vector (300, 300, 300); - pev->gravity = 1;// normal gravity now - - // HACKHACK - On ground isn't always set, so look for ground underneath - TraceResult tr; - UTIL_TraceLine( pev->origin, pev->origin - Vector(0,0,10), ignore_monsters, edict(), &tr ); - - if ( tr.flFraction < 1.0 ) - { - // add a bit of static friction - pev->velocity = pev->velocity * 0.95; - pev->avelocity = pev->avelocity * 0.9; - // play sliding sound, volume based on velocity - } - if ( !(pev->flags & FL_ONGROUND) && pev->velocity.Length2D() > 10 ) - { - BounceSound(); - } - StudioFrameAdvance( ); -} - - -void CSatchelCharge :: SatchelThink( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (!IsInWorld()) - { - UTIL_Remove( this ); - return; - } - - if (pev->waterlevel == 3) - { - pev->movetype = MOVETYPE_FLY; - pev->velocity = pev->velocity * 0.8; - pev->avelocity = pev->avelocity * 0.9; - pev->velocity.z += 8; - } - else if (pev->waterlevel == 0) - { - pev->movetype = MOVETYPE_BOUNCE; - } - else - { - pev->velocity.z -= 8; - } -} - -void CSatchelCharge :: Precache( void ) -{ - PRECACHE_MODEL("models/grenade.mdl"); - PRECACHE_SOUND("weapons/g_bounce1.wav"); - PRECACHE_SOUND("weapons/g_bounce2.wav"); - PRECACHE_SOUND("weapons/g_bounce3.wav"); -} - -void CSatchelCharge :: BounceSound( void ) -{ - switch ( RANDOM_LONG( 0, 2 ) ) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/g_bounce3.wav", 1, ATTN_NORM); break; - } -} - - -LINK_ENTITY_TO_CLASS( weapon_satchel, CSatchel ); - - -//========================================================= -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -//========================================================= -int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - CSatchel *pSatchel; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - pSatchel = (CSatchel *)pOriginal; - - if ( pSatchel->m_chargeReady != 0 ) - { - // player has some satchels deployed. Refuse to add more. - return FALSE; - } - } - - return CBasePlayerWeapon::AddDuplicate ( pOriginal ); -} - -//========================================================= -//========================================================= -int CSatchel::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= (1<pszName = STRING(pev->classname); - p->pszAmmo1 = "Satchel Charge"; - p->iMaxAmmo1 = SATCHEL_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 1; - p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - p->iId = m_iId = WEAPON_SATCHEL; - p->iWeight = SATCHEL_WEIGHT; - - return 1; -} - -//========================================================= -//========================================================= -BOOL CSatchel::IsUseable( void ) -{ - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) - { - // player is carrying some satchels - return TRUE; - } - - if ( m_chargeReady != 0 ) - { - // player isn't carrying any satchels, but has some out - return TRUE; - } - - return FALSE; -} - -BOOL CSatchel::CanDeploy( void ) -{ - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] > 0 ) - { - // player is carrying some satchels - return TRUE; - } - - if ( m_chargeReady != 0 ) - { - // player isn't carrying any satchels, but has some out - return TRUE; - } - - return FALSE; -} - -BOOL CSatchel::Deploy( ) -{ - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - - if ( m_chargeReady ) - return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" ); - else - return DefaultDeploy( "models/v_satchel.mdl", "models/p_satchel.mdl", SATCHEL_DRAW, "trip" ); - - - return TRUE; -} - - -void CSatchel::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( m_chargeReady ) - { - SendWeaponAnim( SATCHEL_RADIO_HOLSTER ); - } - else - { - SendWeaponAnim( SATCHEL_DROP ); - } - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); - - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) - { - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - } -} - - - -void CSatchel::PrimaryAttack() -{ - switch (m_chargeReady) - { - case 0: - { - Throw( ); - } - break; - case 1: - { - SendWeaponAnim( SATCHEL_RADIO_FIRE ); - - edict_t *pPlayer = m_pPlayer->edict( ); - - CBaseEntity *pSatchel = NULL; - - while ((pSatchel = UTIL_FindEntityInSphere( pSatchel, m_pPlayer->pev->origin, 4096 )) != NULL) - { - if (FClassnameIs( pSatchel->pev, "monster_satchel")) - { - if (pSatchel->pev->owner == pPlayer) - { - pSatchel->Use( m_pPlayer, m_pPlayer, USE_ON, 0 ); - m_chargeReady = 2; - } - } - } - - m_chargeReady = 2; - m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - break; - } - - case 2: - // we're reloading, don't allow fire - { - } - break; - } -} - - -void CSatchel::SecondaryAttack( void ) -{ - if ( m_chargeReady != 2 ) - { - Throw( ); - } -} - - -void CSatchel::Throw( void ) -{ - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { -#ifndef CLIENT_DLL - Vector vecSrc = m_pPlayer->pev->origin; - Vector vecThrow = gpGlobals->v_forward * 274 + m_pPlayer->pev->velocity; - CBaseEntity *pSatchel = Create( "monster_satchel", vecSrc, Vector( 0, 0, 0), m_pPlayer->edict() ); - pSatchel->pev->velocity = vecThrow; - pSatchel->pev->avelocity.y = 400; - - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel_radio.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel_radio.mdl"); -#else - LoadVModel ( "models/v_satchel_radio.mdl", m_pPlayer ); -#endif - - SendWeaponAnim( SATCHEL_RADIO_DRAW ); - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - m_chargeReady = 1; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_flNextPrimaryAttack = GetNextAttackDelay(1.0); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - } -} - - -void CSatchel::WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - switch( m_chargeReady ) - { - case 0: - SendWeaponAnim( SATCHEL_FIDGET1 ); - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - break; - case 1: - SendWeaponAnim( SATCHEL_RADIO_FIDGET1 ); - // use hivehand animations - strcpy( m_pPlayer->m_szAnimExtention, "hive" ); - break; - case 2: - if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] ) - { - m_chargeReady = 0; - RetireWeapon(); - return; - } - -#ifndef CLIENT_DLL - m_pPlayer->pev->viewmodel = MAKE_STRING("models/v_satchel.mdl"); - m_pPlayer->pev->weaponmodel = MAKE_STRING("models/p_satchel.mdl"); -#else - LoadVModel ( "models/v_satchel.mdl", m_pPlayer ); -#endif - - SendWeaponAnim( SATCHEL_DRAW ); - - // use tripmine animations - strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - - m_flNextPrimaryAttack = GetNextAttackDelay(0.5); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; - m_chargeReady = 0; - break; - } - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. -} - -//========================================================= -// DeactivateSatchels - removes all satchels owned by -// the provided player. Should only be used upon death. -// -// Made this global on purpose. -//========================================================= -void DeactivateSatchels( CBasePlayer *pOwner ) -{ - edict_t *pFind; - - pFind = FIND_ENTITY_BY_CLASSNAME( NULL, "monster_satchel" ); - - while ( !FNullEnt( pFind ) ) - { - CBaseEntity *pEnt = CBaseEntity::Instance( pFind ); - CSatchelCharge *pSatchel = (CSatchelCharge *)pEnt; - - if ( pSatchel ) - { - if ( pSatchel->pev->owner == pOwner->edict() ) - { - pSatchel->Deactivate(); - } - } - - pFind = FIND_ENTITY_BY_CLASSNAME( pFind, "monster_satchel" ); - } -} - -#endif diff --git a/sdk/dlls/saverestore.h b/sdk/dlls/saverestore.h deleted file mode 100644 index 5ca9148..0000000 --- a/sdk/dlls/saverestore.h +++ /dev/null @@ -1,176 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Implementation in UTIL.CPP -#ifndef SAVERESTORE_H -#define SAVERESTORE_H - -class CBaseEntity; - -class CSaveRestoreBuffer -{ -public: - CSaveRestoreBuffer( void ); - CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); - virtual ~CSaveRestoreBuffer( void ); - - int EntityIndex( entvars_t *pevLookup ); - int EntityIndex( edict_t *pentLookup ); - int EntityIndex( EOFFSET eoLookup ); - int EntityIndex( CBaseEntity *pEntity ); - - int EntityFlags( int entityIndex, int flags ) { return EntityFlagsSet( entityIndex, 0 ); } - int EntityFlagsSet( int entityIndex, int flags ); - - edict_t *EntityFromIndex( int entityIndex ); - - unsigned short TokenHash( const char *pszToken ); - -protected: - SAVERESTOREDATA *m_pdata; - void BufferRewind( int size ); - unsigned int HashString( const char *pszToken ); -private: - // effc++ rule 11 - void operator=(CSaveRestoreBuffer&); - CSaveRestoreBuffer(const CSaveRestoreBuffer&); -}; - - -class CSave : public CSaveRestoreBuffer -{ -public: - CSave( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) {}; - - void WriteShort( const char *pname, const short *value, int count ); - void WriteInt( const char *pname, const int *value, int count ); // Save an int - void WriteFloat( const char *pname, const float *value, int count ); // Save a float - void WriteTime( const char *pname, const float *value, int count ); // Save a float (timevalue) - void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block - void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string - void WriteString( const char *pname, const int *stringId, int count ); // Save a null-terminated string (engine string) - void WriteVector( const char *pname, const Vector &value ); // Save a vector - void WriteVector( const char *pname, const float *value, int count ); // Save a vector - void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary - void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors - void WriteFunction( const char *pname, void **value, int count ); // Save a function pointer - int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) - int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - -private: - int DataEmpty( const char *pdata, int size ); - void BufferField( const char *pname, int size, const char *pdata ); - void BufferString( char *pdata, int len ); - void BufferData( const char *pdata, int size ); - void BufferHeader( const char *pname, int size ); -}; - -typedef struct -{ - unsigned short size; - unsigned short token; - char *pData; -} HEADER; - -class CRestore : public CSaveRestoreBuffer -{ -public: - CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ), m_global(0), m_precache(TRUE) { } - int ReadEntVars( const char *pname, entvars_t *pev ); // entvars_t - int ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); - int ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ); - int ReadInt( void ); - short ReadShort( void ); - int ReadNamedInt( const char *pName ); - char *ReadNamedString( const char *pName ); - int Empty( void ) { return (m_pdata == NULL) || ((m_pdata->pCurrentData-m_pdata->pBaseData)>=m_pdata->bufferSize); } - inline void SetGlobalMode( int global ) { m_global = global; } - void PrecacheMode( BOOL mode ) { m_precache = mode; } - -private: - char *BufferPointer( void ); - void BufferReadBytes( char *pOutput, int size ); - void BufferSkipBytes( int bytes ); - int BufferSkipZString( void ); - int BufferCheckZString( const char *string ); - - void BufferReadHeader( HEADER *pheader ); - - int m_global; // Restoring a global entity? - BOOL m_precache; -}; - -#define MAX_ENTITYARRAY 64 - -//#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) - -#define IMPLEMENT_SAVERESTORE(derivedClass,baseClass) \ - int derivedClass::Save( CSave &save )\ - {\ - if ( !baseClass::Save(save) )\ - return 0;\ - return save.WriteFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - }\ - int derivedClass::Restore( CRestore &restore )\ - {\ - if ( !baseClass::Restore(restore) )\ - return 0;\ - return restore.ReadFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ - } - - -typedef enum { GLOBAL_OFF = 0, GLOBAL_ON = 1, GLOBAL_DEAD = 2 } GLOBALESTATE; - -typedef struct globalentity_s globalentity_t; - -struct globalentity_s -{ - char name[64]; - char levelName[32]; - GLOBALESTATE state; - globalentity_t *pNext; -}; - -class CGlobalState -{ -public: - CGlobalState(); - void Reset( void ); - void ClearStates( void ); - void EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ); - void EntitySetState( string_t globalname, GLOBALESTATE state ); - void EntityUpdate( string_t globalname, string_t mapname ); - const globalentity_t *EntityFromTable( string_t globalname ); - GLOBALESTATE EntityGetState( string_t globalname ); - int EntityInTable( string_t globalname ) { return (Find( globalname ) != NULL) ? 1 : 0; } - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -//#ifdef _DEBUG - void DumpGlobals( void ); -//#endif - -private: - globalentity_t *Find( string_t globalname ); - globalentity_t *m_pList; - int m_listCount; - // effc++ rule 11 - void operator=(CGlobalState&); - CGlobalState(const CGlobalState&); -}; - -extern CGlobalState gGlobalState; - -#endif //SAVERESTORE_H diff --git a/sdk/dlls/schedule.cpp b/sdk/dlls/schedule.cpp deleted file mode 100644 index ccbe44e..0000000 --- a/sdk/dlls/schedule.cpp +++ /dev/null @@ -1,1514 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// schedule.cpp - functions and data pertaining to the -// monsters' AI scheduling system. -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "animation.h" -#include "scripted.h" -#include "nodes.h" -#include "defaultai.h" -#include "soundent.h" - -extern CGraph WorldGraph; - -//========================================================= -// FHaveSchedule - Returns TRUE if monster's m_pSchedule -// is anything other than NULL. -//========================================================= -BOOL CBaseMonster :: FHaveSchedule( void ) -{ - if ( m_pSchedule == NULL ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -// ClearSchedule - blanks out the caller's schedule pointer -// and index. -//========================================================= -void CBaseMonster :: ClearSchedule( void ) -{ - m_iTaskStatus = TASKSTATUS_NEW; - m_pSchedule = NULL; - m_iScheduleIndex = 0; -} - -//========================================================= -// FScheduleDone - Returns TRUE if the caller is on the -// last task in the schedule -//========================================================= -BOOL CBaseMonster :: FScheduleDone ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - if ( m_iScheduleIndex == m_pSchedule->cTasks ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// ChangeSchedule - replaces the monster's schedule pointer -// with the passed pointer, and sets the ScheduleIndex back -// to 0 -//========================================================= -void CBaseMonster :: ChangeSchedule ( Schedule_t *pNewSchedule ) -{ - ASSERT( pNewSchedule != NULL ); - - m_pSchedule = pNewSchedule; - m_iScheduleIndex = 0; - m_iTaskStatus = TASKSTATUS_NEW; - m_afConditions = 0;// clear all of the conditions - m_failSchedule = SCHED_NONE; - - if ( m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND && !(m_pSchedule->iSoundMask) ) - { - ALERT ( at_aiconsole, "COND_HEAR_SOUND with no sound mask!\n" ); - } - else if ( m_pSchedule->iSoundMask && !(m_pSchedule->iInterruptMask & bits_COND_HEAR_SOUND) ) - { - ALERT ( at_aiconsole, "Sound mask without COND_HEAR_SOUND!\n" ); - } - -#if _DEBUG - if ( !ScheduleFromName( pNewSchedule->pName ) ) - { - ALERT( at_console, "Schedule %s not in table!!!\n", pNewSchedule->pName ); - } -#endif - -// this is very useful code if you can isolate a test case in a level with a single monster. It will notify -// you of every schedule selection the monster makes. -#if 0 - if ( FClassnameIs( pev, "monster_human_grunt" ) ) - { - Task_t *pTask = GetTask(); - - if ( pTask ) - { - const char *pName = NULL; - - if ( m_pSchedule ) - { - pName = m_pSchedule->pName; - } - else - { - pName = "No Schedule"; - } - - if ( !pName ) - { - pName = "Unknown"; - } - - ALERT( at_aiconsole, "%s: picked schedule %s\n", STRING( pev->classname ), pName ); - } - } -#endif// 0 - -} - -//========================================================= -// NextScheduledTask - increments the ScheduleIndex -//========================================================= -void CBaseMonster :: NextScheduledTask ( void ) -{ - ASSERT( m_pSchedule != NULL ); - - m_iTaskStatus = TASKSTATUS_NEW; - m_iScheduleIndex++; - - if ( FScheduleDone() ) - { - // just completed last task in schedule, so make it invalid by clearing it. - SetConditions( bits_COND_SCHEDULE_DONE ); - //ClearSchedule(); - } -} - -//========================================================= -// IScheduleFlags - returns an integer with all Conditions -// bits that are currently set and also set in the current -// schedule's Interrupt mask. -//========================================================= -int CBaseMonster :: IScheduleFlags ( void ) -{ - if( !m_pSchedule ) - { - return 0; - } - - // strip off all bits excepts the ones capable of breaking this schedule. - return m_afConditions & m_pSchedule->iInterruptMask; -} - -//========================================================= -// FScheduleValid - returns TRUE as long as the current -// schedule is still the proper schedule to be executing, -// taking into account all conditions -//========================================================= -BOOL CBaseMonster :: FScheduleValid ( void ) -{ - if ( m_pSchedule == NULL ) - { - // schedule is empty, and therefore not valid. - return FALSE; - } - - if ( HasConditions( m_pSchedule->iInterruptMask | bits_COND_SCHEDULE_DONE | bits_COND_TASK_FAILED ) ) - { -#ifdef DEBUG - if ( HasConditions ( bits_COND_TASK_FAILED ) && m_failSchedule == SCHED_NONE ) - { - // fail! Send a visual indicator. - ALERT ( at_aiconsole, "Schedule: %s Failed\n", m_pSchedule->pName ); - - Vector tmp = pev->origin; - tmp.z = pev->absmax.z + 16; - UTIL_Sparks( tmp ); - } -#endif // DEBUG - - // some condition has interrupted the schedule, or the schedule is done - return FALSE; - } - - return TRUE; -} - -//========================================================= -// MaintainSchedule - does all the per-think schedule maintenance. -// ensures that the monster leaves this function with a valid -// schedule! -//========================================================= -void CBaseMonster :: MaintainSchedule ( void ) -{ - Schedule_t *pNewSchedule; - int i; - - // UNDONE: Tune/fix this 10... This is just here so infinite loops are impossible - for ( i = 0; i < 10; i++ ) - { - if ( m_pSchedule != NULL && TaskIsComplete() ) - { - NextScheduledTask(); - } - - // validate existing schedule - if ( !FScheduleValid() || m_MonsterState != m_IdealMonsterState ) - { - // if we come into this block of code, the schedule is going to have to be changed. - // if the previous schedule was interrupted by a condition, GetIdealState will be - // called. Else, a schedule finished normally. - - // Notify the monster that his schedule is changing - ScheduleChange(); - - // Call GetIdealState if we're not dead and one or more of the following... - // - in COMBAT state with no enemy (it died?) - // - conditions bits (excluding SCHEDULE_DONE) indicate interruption, - // - schedule is done but schedule indicates it wants GetIdealState called - // after successful completion (by setting bits_COND_SCHEDULE_DONE in iInterruptMask) - // DEAD & SCRIPT are not suggestions, they are commands! - if ( m_IdealMonsterState != MONSTERSTATE_DEAD && - (m_IdealMonsterState != MONSTERSTATE_SCRIPT || m_IdealMonsterState == m_MonsterState) ) - { - if ( (m_afConditions && !HasConditions(bits_COND_SCHEDULE_DONE)) || - (m_pSchedule && (m_pSchedule->iInterruptMask & bits_COND_SCHEDULE_DONE)) || - ((m_MonsterState == MONSTERSTATE_COMBAT) && (m_hEnemy == 0)) ) - { - GetIdealState(); - } - } - if ( HasConditions( bits_COND_TASK_FAILED ) && m_MonsterState == m_IdealMonsterState ) - { - if ( m_failSchedule != SCHED_NONE ) - pNewSchedule = GetScheduleOfType( m_failSchedule ); - else - pNewSchedule = GetScheduleOfType( SCHED_FAIL ); - // schedule was invalid because the current task failed to start or complete - ALERT ( at_aiconsole, "Schedule Failed at %d!\n", m_iScheduleIndex ); - ChangeSchedule( pNewSchedule ); - } - else - { - SetState( m_IdealMonsterState ); - if ( m_MonsterState == MONSTERSTATE_SCRIPT || m_MonsterState == MONSTERSTATE_DEAD ) - pNewSchedule = CBaseMonster::GetSchedule(); - else - pNewSchedule = GetSchedule(); - ChangeSchedule( pNewSchedule ); - } - } - - if ( m_iTaskStatus == TASKSTATUS_NEW ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - TaskBegin(); - StartTask( pTask ); - } - - // UNDONE: Twice?!!! - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } - - if ( !TaskIsComplete() && m_iTaskStatus != TASKSTATUS_NEW ) - break; - } - - if ( TaskIsRunning() ) - { - Task_t *pTask = GetTask(); - ASSERT( pTask != NULL ); - RunTask( pTask ); - } - - // UNDONE: We have to do this so that we have an animation set to blend to if RunTask changes the animation - // RunTask() will always change animations at the end of a script! - // Don't do this twice - if ( m_Activity != m_IdealActivity ) - { - SetActivity ( m_IdealActivity ); - } -} - -//========================================================= -// RunTask -//========================================================= -void CBaseMonster :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - case TASK_TURN_LEFT: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - { - CBaseEntity *pTarget; - - if ( pTask->iTask == TASK_PLAY_SEQUENCE_FACE_TARGET ) - pTarget = m_hTargetEnt; - else - pTarget = m_hEnemy; - if ( pTarget ) - { - pev->ideal_yaw = UTIL_VecToYaw( pTarget->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - if ( m_fSequenceFinished ) - TaskComplete(); - } - break; - - case TASK_PLAY_SEQUENCE: - case TASK_PLAY_ACTIVE_IDLE: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - break; - } - - - case TASK_FACE_ENEMY: - { - MakeIdealYaw( m_vecEnemyLKP ); - - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_FACE_HINTNODE: - case TASK_FACE_LASTPOSITION: - case TASK_FACE_TARGET: - case TASK_FACE_IDEAL: - case TASK_FACE_ROUTE: - { - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_PVS: - { - if ( !FNullEnt(FIND_CLIENT_IN_PVS(edict())) ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_RANDOM: - { - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_WAIT_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw( pev->yaw_speed ); - - if ( gpGlobals->time >= m_flWaitFinished ) - { - TaskComplete(); - } - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - float distance; - - if ( m_hTargetEnt == 0 ) - TaskFail(); - else - { - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK ) - m_movementActivity = ACT_WALK; - else if ( distance >= 270 && m_movementActivity != ACT_RUN ) - m_movementActivity = ACT_RUN; - } - - break; - } - case TASK_WAIT_FOR_MOVEMENT: - { - if (MovementIsComplete()) - { - TaskComplete(); - RouteClear(); // Stop moving - } - break; - } - case TASK_DIE: - { - if ( m_fSequenceFinished && pev->frame >= 255 ) - { - pev->deadflag = DEAD_DEAD; - - SetThink ( NULL ); - StopAnimation(); - - if ( !BBoxFlat() ) - { - // a bit of a hack. If a corpses' bbox is positioned such that being left solid so that it can be attacked will - // block the player on a slope or stairs, the corpse is made nonsolid. -// pev->solid = SOLID_NOT; - UTIL_SetSize ( pev, Vector ( -4, -4, 0 ), Vector ( 4, 4, 1 ) ); - } - else // !!!HACKHACK - put monster in a thin, wide bounding box until we fix the solid type/bounding volume problem - UTIL_SetSize ( pev, Vector ( pev->mins.x, pev->mins.y, pev->mins.z ), Vector ( pev->maxs.x, pev->maxs.y, pev->mins.z + 1 ) ); - - if ( ShouldFadeOnDeath() ) - { - // this monster was created by a monstermaker... fade the corpse out. - SUB_StartFadeOut(); - } - else - { - // body is gonna be around for a while, so have it stink for a bit. - CSoundEnt::InsertSound ( bits_SOUND_CARCASS, pev->origin, 384, 30 ); - } - } - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RELOAD_NOTURN: - { - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_RANGE_ATTACK1: - case TASK_MELEE_ATTACK1: - case TASK_MELEE_ATTACK2: - case TASK_RANGE_ATTACK2: - case TASK_SPECIAL_ATTACK1: - case TASK_SPECIAL_ATTACK2: - case TASK_RELOAD: - { - MakeIdealYaw ( m_vecEnemyLKP ); - ChangeYaw ( pev->yaw_speed ); - - if ( m_fSequenceFinished ) - { - m_Activity = ACT_RESET; - TaskComplete(); - } - break; - } - case TASK_SMALL_FLINCH: - { - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - } - break; - case TASK_WAIT_FOR_SCRIPT: - { - if ( m_pCine->m_iDelay <= 0 && gpGlobals->time >= m_pCine->m_startTime ) - { - TaskComplete(); - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszPlay, TRUE ); - if ( m_fSequenceFinished ) - ClearSchedule(); - pev->framerate = 1.0; - //ALERT( at_aiconsole, "Script %s has begun for %s\n", STRING( m_pCine->m_iszPlay ), STRING(pev->classname) ); - } - break; - } - case TASK_PLAY_SCRIPT: - { - if (m_fSequenceFinished) - { - m_pCine->SequenceDone( this ); - } - break; - } - } -} - -//========================================================= -// SetTurnActivity - measures the difference between the way -// the monster is facing and determines whether or not to -// select one of the 180 turn animations. -//========================================================= -void CBaseMonster :: SetTurnActivity ( void ) -{ - float flYD; - flYD = FlYawDiff(); - - if ( flYD <= -45 && LookupActivity ( ACT_TURN_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) - {// big right turn - m_IdealActivity = ACT_TURN_RIGHT; - } - else if ( flYD > 45 && LookupActivity ( ACT_TURN_LEFT ) != ACTIVITY_NOT_AVAILABLE ) - {// big left turn - m_IdealActivity = ACT_TURN_LEFT; - } -} - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. -//========================================================= -void CBaseMonster :: StartTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TURN_RIGHT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw - pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_TURN_LEFT: - { - float flCurrentYaw; - - flCurrentYaw = UTIL_AngleMod( pev->angles.y ); - pev->ideal_yaw = UTIL_AngleMod( flCurrentYaw + pTask->flData ); - SetTurnActivity(); - break; - } - case TASK_REMEMBER: - { - Remember ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FORGET: - { - Forget ( (int)pTask->flData ); - TaskComplete(); - break; - } - case TASK_FIND_HINTNODE: - { - m_iHintNode = FindHintNode(); - - if ( m_iHintNode != NO_NODE ) - { - TaskComplete(); - } - else - { - TaskFail(); - } - break; - } - case TASK_STORE_LASTPOSITION: - { - m_vecLastPosition = pev->origin; - TaskComplete(); - break; - } - case TASK_CLEAR_LASTPOSITION: - { - m_vecLastPosition = g_vecZero; - TaskComplete(); - break; - } - case TASK_CLEAR_HINTNODE: - { - m_iHintNode = NO_NODE; - TaskComplete(); - break; - } - case TASK_STOP_MOVING: - { - if ( m_IdealActivity == m_movementActivity ) - { - m_IdealActivity = GetStoppedActivity(); - } - - RouteClear(); - TaskComplete(); - break; - } - case TASK_PLAY_SEQUENCE_FACE_ENEMY: - case TASK_PLAY_SEQUENCE_FACE_TARGET: - case TASK_PLAY_SEQUENCE: - { - m_IdealActivity = ( Activity )( int )pTask->flData; - break; - } - case TASK_PLAY_ACTIVE_IDLE: - { - // monsters verify that they have a sequence for the node's activity BEFORE - // moving towards the node, so it's ok to just set the activity without checking here. - m_IdealActivity = ( Activity )WorldGraph.m_pNodes[ m_iHintNode ].m_sHintActivity; - break; - } - case TASK_SET_SCHEDULE: - { - Schedule_t *pNewSchedule; - - pNewSchedule = GetScheduleOfType( (int)pTask->flData ); - - if ( pNewSchedule ) - { - ChangeSchedule( pNewSchedule ); - } - else - { - TaskFail(); - } - - break; - } - case TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == 0 ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, pTask->flData ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_FAR_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == 0 ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, pTask->flData, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_NODE_COVER_FROM_ENEMY: - { - if ( m_hEnemy == 0 ) - { - TaskFail(); - return; - } - - if ( FindCover( m_hEnemy->pev->origin, m_hEnemy->pev->view_ofs, 0, CoverRadius() ) ) - { - // try for cover farther than the FLData from the schedule. - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ENEMY: - { - entvars_t *pevCover; - - if ( m_hEnemy == 0 ) - { - // Find cover from self if no enemy available - pevCover = pev; -// TaskFail(); -// return; - } - else - pevCover = m_hEnemy->pev; - - if ( FindLateralCover( pevCover->origin, pevCover->view_ofs ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else if ( FindCover( pevCover->origin, pevCover->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. - TaskFail(); - } - break; - } - case TASK_FIND_COVER_FROM_ORIGIN: - { - if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no cover! - TaskFail(); - } - } - break; - case TASK_FIND_COVER_FROM_BEST_SOUND: - { - CSound *pBestSound; - - pBestSound = PBestSound(); - - ASSERT( pBestSound != NULL ); - /* - if ( pBestSound && FindLateralCover( pBestSound->m_vecOrigin, g_vecZero ) ) - { - // try lateral first - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - */ - - if ( pBestSound && FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + pTask->flData; - TaskComplete(); - } - else - { - // no coverwhatsoever. or no sound in list - TaskFail(); - } - break; - } - case TASK_FACE_HINTNODE: - { - pev->ideal_yaw = WorldGraph.m_pNodes[ m_iHintNode ].m_flHintYaw; - SetTurnActivity(); - break; - } - - case TASK_FACE_LASTPOSITION: - MakeIdealYaw ( m_vecLastPosition ); - SetTurnActivity(); - break; - - case TASK_FACE_TARGET: - if ( m_hTargetEnt != 0 ) - { - MakeIdealYaw ( m_hTargetEnt->pev->origin ); - SetTurnActivity(); - } - else - TaskFail(); - break; - case TASK_FACE_ENEMY: - { - MakeIdealYaw ( m_vecEnemyLKP ); - SetTurnActivity(); - break; - } - case TASK_FACE_IDEAL: - { - SetTurnActivity(); - break; - } - case TASK_FACE_ROUTE: - { - if (FRouteClear()) - { - ALERT(at_aiconsole, "No route to face!\n"); - TaskFail(); - } - else - { - MakeIdealYaw(m_Route[m_iRouteIndex].vecLocation); - SetTurnActivity(); - } - break; - } - case TASK_WAIT_PVS: - case TASK_WAIT_INDEFINITE: - { - // don't do anything. - break; - } - case TASK_WAIT: - case TASK_WAIT_FACE_ENEMY: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - } - case TASK_WAIT_RANDOM: - {// set a future time that tells us when the wait is over. - m_flWaitFinished = gpGlobals->time + RANDOM_FLOAT( 0.1, pTask->flData ); - break; - } - case TASK_MOVE_TO_TARGET_RANGE: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK, 2 ) ) - TaskFail(); - } - break; - } - case TASK_RUN_TO_TARGET: - case TASK_WALK_TO_TARGET: - { - Activity newActivity; - - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - if ( pTask->iTask == TASK_WALK_TO_TARGET ) - newActivity = ACT_WALK; - else - newActivity = ACT_RUN; - // This monster can't do this! - if ( LookupActivity( newActivity ) == ACTIVITY_NOT_AVAILABLE ) - TaskComplete(); - else - { - if ( m_hTargetEnt == 0 || !MoveToTarget( newActivity, 2 ) ) - { - TaskFail(); - ALERT( at_aiconsole, "%s Failed to reach target!!!\n", STRING(pev->classname) ); - RouteClear(); - } - } - } - TaskComplete(); - break; - } - case TASK_CLEAR_MOVE_WAIT: - { - m_flMoveWaitFinished = gpGlobals->time; - TaskComplete(); - break; - } - case TASK_MELEE_ATTACK1_NOTURN: - case TASK_MELEE_ATTACK1: - { - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - } - case TASK_MELEE_ATTACK2_NOTURN: - case TASK_MELEE_ATTACK2: - { - m_IdealActivity = ACT_MELEE_ATTACK2; - break; - } - case TASK_RANGE_ATTACK1_NOTURN: - case TASK_RANGE_ATTACK1: - { - m_IdealActivity = ACT_RANGE_ATTACK1; - break; - } - case TASK_RANGE_ATTACK2_NOTURN: - case TASK_RANGE_ATTACK2: - { - m_IdealActivity = ACT_RANGE_ATTACK2; - break; - } - case TASK_RELOAD_NOTURN: - case TASK_RELOAD: - { - m_IdealActivity = ACT_RELOAD; - break; - } - case TASK_SPECIAL_ATTACK1: - { - m_IdealActivity = ACT_SPECIAL_ATTACK1; - break; - } - case TASK_SPECIAL_ATTACK2: - { - m_IdealActivity = ACT_SPECIAL_ATTACK2; - break; - } - case TASK_SET_ACTIVITY: - { - m_IdealActivity = (Activity)(int)pTask->flData; - TaskComplete(); - break; - } - case TASK_GET_PATH_TO_ENEMY_LKP: - { - if ( BuildRoute ( m_vecEnemyLKP, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( m_vecEnemyLKP, pev->view_ofs, 0, (m_vecEnemyLKP - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemyLKP failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY: - { - CBaseEntity *pEnemy = m_hEnemy; - - if ( pEnemy == NULL ) - { - TaskFail(); - return; - } - - if ( BuildRoute ( pEnemy->pev->origin, bits_MF_TO_ENEMY, pEnemy ) ) - { - TaskComplete(); - } - else if (BuildNearestRoute( pEnemy->pev->origin, pEnemy->pev->view_ofs, 0, (pEnemy->pev->origin - pev->origin).Length() )) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToEnemy failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_ENEMY_CORPSE: - { - UTIL_MakeVectors( pev->angles ); - if ( BuildRoute ( m_vecEnemyLKP - gpGlobals->v_forward * 64, bits_MF_TO_LOCATION, NULL ) ) - { - TaskComplete(); - } - else - { - ALERT ( at_aiconsole, "GetPathToEnemyCorpse failed!!\n" ); - TaskFail(); - } - } - break; - case TASK_GET_PATH_TO_SPOT: - { - CBaseEntity *pPlayer = CBaseEntity::Instance( FIND_ENTITY_BY_CLASSNAME( NULL, "player" ) ); - if ( BuildRoute ( m_vecMoveGoal, bits_MF_TO_LOCATION, pPlayer ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - - case TASK_GET_PATH_TO_TARGET: - { - RouteClear(); - if ( m_hTargetEnt != 0 && MoveToTarget( m_movementActivity, 1 ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToSpot failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_HINTNODE:// for active idles! - { - if ( MoveToLocation( m_movementActivity, 2, WorldGraph.m_pNodes[ m_iHintNode ].m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToHintNode failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_LASTPOSITION: - { - m_vecMoveGoal = m_vecLastPosition; - - if ( MoveToLocation( m_movementActivity, 2, m_vecMoveGoal ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToLastPosition failed!!\n" ); - TaskFail(); - } - break; - } - case TASK_GET_PATH_TO_BESTSOUND: - { - CSound *pSound; - - pSound = PBestSound(); - - if ( pSound && MoveToLocation( m_movementActivity, 2, pSound->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestSound failed!!\n" ); - TaskFail(); - } - break; - } -case TASK_GET_PATH_TO_BESTSCENT: - { - CSound *pScent; - - pScent = PBestScent(); - - if ( pScent && MoveToLocation( m_movementActivity, 2, pScent->m_vecOrigin ) ) - { - TaskComplete(); - } - else - { - // no way to get there =( - ALERT ( at_aiconsole, "GetPathToBestScent failed!!\n" ); - - TaskFail(); - } - break; - } - case TASK_RUN_PATH: - { - // UNDONE: This is in some default AI and some monsters can't run? -- walk instead? - if ( LookupActivity( ACT_RUN ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_RUN; - } - else - { - m_movementActivity = ACT_WALK; - } - TaskComplete(); - break; - } - case TASK_WALK_PATH: - { - if ( pev->movetype == MOVETYPE_FLY ) - { - m_movementActivity = ACT_FLY; - } - if ( LookupActivity( ACT_WALK ) != ACTIVITY_NOT_AVAILABLE ) - { - m_movementActivity = ACT_WALK; - } - else - { - m_movementActivity = ACT_RUN; - } - TaskComplete(); - break; - } - case TASK_STRAFE_PATH: - { - Vector2D vec2DirToPoint; - Vector2D vec2RightSide; - - // to start strafing, we have to first figure out if the target is on the left side or right side - UTIL_MakeVectors ( pev->angles ); - - vec2DirToPoint = ( m_Route[ 0 ].vecLocation - pev->origin ).Make2D().Normalize(); - vec2RightSide = gpGlobals->v_right.Make2D().Normalize(); - - if ( DotProduct ( vec2DirToPoint, vec2RightSide ) > 0 ) - { - // strafe right - m_movementActivity = ACT_STRAFE_RIGHT; - } - else - { - // strafe left - m_movementActivity = ACT_STRAFE_LEFT; - } - TaskComplete(); - break; - } - - - case TASK_WAIT_FOR_MOVEMENT: - { - if (FRouteClear()) - { - TaskComplete(); - } - break; - } - - case TASK_EAT: - { - Eat( pTask->flData ); - TaskComplete(); - break; - } - case TASK_SMALL_FLINCH: - { - m_IdealActivity = GetSmallFlinchActivity(); - break; - } - case TASK_DIE: - { - RouteClear(); - - m_IdealActivity = GetDeathActivity(); - - pev->deadflag = DEAD_DYING; - break; - } - case TASK_SOUND_WAKE: - { - AlertSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DIE: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_IDLE: - { - IdleSound(); - TaskComplete(); - break; - } - case TASK_SOUND_PAIN: - { - PainSound(); - TaskComplete(); - break; - } - case TASK_SOUND_DEATH: - { - DeathSound(); - TaskComplete(); - break; - } - case TASK_SOUND_ANGRY: - { - // sounds are complete as soon as we get here, cause we've already played them. - ALERT ( at_aiconsole, "SOUND\n" ); - TaskComplete(); - break; - } - case TASK_WAIT_FOR_SCRIPT: - { - if (m_pCine->m_iszIdle) - { - m_pCine->StartSequence( (CBaseMonster *)this, m_pCine->m_iszIdle, FALSE ); - if (FStrEq( STRING(m_pCine->m_iszIdle), STRING(m_pCine->m_iszPlay))) - { - pev->framerate = 0; - } - } - else - m_IdealActivity = ACT_IDLE; - - break; - } - case TASK_PLAY_SCRIPT: - { - pev->movetype = MOVETYPE_FLY; - ClearBits(pev->flags, FL_ONGROUND); - m_scriptState = SCRIPT_PLAYING; - break; - } - case TASK_ENABLE_SCRIPT: - { - m_pCine->DelayStart( 0 ); - TaskComplete(); - break; - } - case TASK_PLANT_ON_SCRIPT: - { - if ( m_hTargetEnt != 0 ) - { - pev->origin = m_hTargetEnt->pev->origin; // Plant on target - } - - TaskComplete(); - break; - } - case TASK_FACE_SCRIPT: - { - if ( m_hTargetEnt != 0 ) - { - pev->ideal_yaw = UTIL_AngleMod( m_hTargetEnt->pev->angles.y ); - } - - TaskComplete(); - m_IdealActivity = ACT_IDLE; - RouteClear(); - break; - } - - case TASK_SUGGEST_STATE: - { - m_IdealMonsterState = (MONSTERSTATE)(int)pTask->flData; - TaskComplete(); - break; - } - - case TASK_SET_FAIL_SCHEDULE: - m_failSchedule = (int)pTask->flData; - TaskComplete(); - break; - - case TASK_CLEAR_FAIL_SCHEDULE: - m_failSchedule = SCHED_NONE; - TaskComplete(); - break; - - default: - { - ALERT ( at_aiconsole, "No StartTask entry for %d\n", (SHARED_TASKS)pTask->iTask ); - break; - } - } -} - -//========================================================= -// GetTask - returns a pointer to the current -// scheduled task. NULL if there's a problem. -//========================================================= -Task_t *CBaseMonster :: GetTask ( void ) -{ - if ( m_iScheduleIndex < 0 || m_iScheduleIndex >= m_pSchedule->cTasks ) - { - // m_iScheduleIndex is not within valid range for the monster's current schedule. - return NULL; - } - else - { - return &m_pSchedule->pTasklist[ m_iScheduleIndex ]; - } -} - -//========================================================= -// GetSchedule - Decides which type of schedule best suits -// the monster's current state and conditions. Then calls -// monster's member function to get a pointer to a schedule -// of the proper type. -//========================================================= -Schedule_t *CBaseMonster :: GetSchedule ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_PRONE: - { - return GetScheduleOfType( SCHED_BARNACLE_VICTIM_GRAB ); - break; - } - case MONSTERSTATE_NONE: - { - ALERT ( at_aiconsole, "MONSTERSTATE IS NONE!\n" ); - break; - } - case MONSTERSTATE_IDLE: - { - if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else if ( FRouteClear() ) - { - // no valid route! - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - else - { - // valid route. Get moving - return GetScheduleOfType( SCHED_IDLE_WALK ); - } - break; - } - case MONSTERSTATE_ALERT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) && LookupActivity( ACT_VICTORY_DANCE ) != ACTIVITY_NOT_AVAILABLE ) - { - return GetScheduleOfType ( SCHED_VICTORY_DANCE ); - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE) ) - { - if ( fabs( FlYawDiff() ) < (1.0 - m_flFieldOfView) * 60 ) // roughly in the correct direction - { - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ORIGIN ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_SMALL_FLINCH ); - } - } - - else if ( HasConditions ( bits_COND_HEAR_SOUND ) ) - { - return GetScheduleOfType( SCHED_ALERT_FACE ); - } - else - { - return GetScheduleOfType( SCHED_ALERT_STAND ); - } - break; - } - case MONSTERSTATE_COMBAT: - { - if ( HasConditions( bits_COND_ENEMY_DEAD ) ) - { - // clear the current (dead) enemy and try to find another. - m_hEnemy = NULL; - - if ( GetEnemy() ) - { - ClearConditions( bits_COND_ENEMY_DEAD ); - return GetSchedule(); - } - else - { - SetState( MONSTERSTATE_ALERT ); - return GetSchedule(); - } - } - - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - return GetScheduleOfType ( SCHED_WAKE_ANGRY ); - } - else if (HasConditions(bits_COND_LIGHT_DAMAGE) && !HasMemory( bits_MEMORY_FLINCHED) ) - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - else if ( !HasConditions(bits_COND_SEE_ENEMY) ) - { - // we can't see the enemy - if ( !HasConditions(bits_COND_ENEMY_OCCLUDED) ) - { - // enemy is unseen, but not occluded! - // turn to face enemy - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - // chase! - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - } - else - { - // we can see the enemy - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_RANGE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK1) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); - } - if ( HasConditions(bits_COND_CAN_MELEE_ATTACK2) ) - { - return GetScheduleOfType( SCHED_MELEE_ATTACK2 ); - } - if ( !HasConditions(bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1) ) - { - // if we can see enemy but can't use either attack type, we must need to get closer to enemy - return GetScheduleOfType( SCHED_CHASE_ENEMY ); - } - else if ( !FacingIdeal() ) - { - //turn - return GetScheduleOfType( SCHED_COMBAT_FACE ); - } - else - { - ALERT ( at_aiconsole, "No suitable combat schedule!\n" ); - } - } - break; - } - case MONSTERSTATE_DEAD: - { - return GetScheduleOfType( SCHED_DIE ); - break; - } - case MONSTERSTATE_SCRIPT: - { - ASSERT( m_pCine != NULL ); - if ( !m_pCine ) - { - ALERT( at_aiconsole, "Script failed for %s\n", STRING(pev->classname) ); - CineCleanup(); - return GetScheduleOfType( SCHED_IDLE_STAND ); - } - - return GetScheduleOfType( SCHED_AISCRIPT ); - } - default: - { - ALERT ( at_aiconsole, "Invalid State for GetSchedule!\n" ); - break; - } - } - - return &slError[ 0 ]; -} diff --git a/sdk/dlls/schedule.h b/sdk/dlls/schedule.h deleted file mode 100644 index b57066b..0000000 --- a/sdk/dlls/schedule.h +++ /dev/null @@ -1,290 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Scheduling -//========================================================= - -#ifndef SCHEDULE_H -#define SCHEDULE_H - -#define TASKSTATUS_NEW 0 // Just started -#define TASKSTATUS_RUNNING 1 // Running task & movement -#define TASKSTATUS_RUNNING_MOVEMENT 2 // Just running movement -#define TASKSTATUS_RUNNING_TASK 3 // Just running task -#define TASKSTATUS_COMPLETE 4 // Completed, get next task - - -//========================================================= -// These are the schedule types -//========================================================= -typedef enum -{ - SCHED_NONE = 0, - SCHED_IDLE_STAND, - SCHED_IDLE_WALK, - SCHED_WAKE_ANGRY, - SCHED_WAKE_CALLED, - SCHED_ALERT_FACE, - SCHED_ALERT_SMALL_FLINCH, - SCHED_ALERT_BIG_FLINCH, - SCHED_ALERT_STAND, - SCHED_INVESTIGATE_SOUND, - SCHED_COMBAT_FACE, - SCHED_COMBAT_STAND, - SCHED_CHASE_ENEMY, - SCHED_CHASE_ENEMY_FAILED, - SCHED_VICTORY_DANCE, - SCHED_TARGET_FACE, - SCHED_TARGET_CHASE, - SCHED_SMALL_FLINCH, - SCHED_TAKE_COVER_FROM_ENEMY, - SCHED_TAKE_COVER_FROM_BEST_SOUND, - SCHED_TAKE_COVER_FROM_ORIGIN, - SCHED_COWER, // usually a last resort! - SCHED_MELEE_ATTACK1, - SCHED_MELEE_ATTACK2, - SCHED_RANGE_ATTACK1, - SCHED_RANGE_ATTACK2, - SCHED_SPECIAL_ATTACK1, - SCHED_SPECIAL_ATTACK2, - SCHED_STANDOFF, - SCHED_ARM_WEAPON, - SCHED_RELOAD, - SCHED_GUARD, - SCHED_AMBUSH, - SCHED_DIE, - SCHED_WAIT_TRIGGER, - SCHED_FOLLOW, - SCHED_SLEEP, - SCHED_WAKE, - SCHED_BARNACLE_VICTIM_GRAB, - SCHED_BARNACLE_VICTIM_CHOMP, - SCHED_AISCRIPT, - SCHED_FAIL, - - LAST_COMMON_SCHEDULE // Leave this at the bottom -} SCHEDULE_TYPE; - -//========================================================= -// These are the shared tasks -//========================================================= -typedef enum -{ - TASK_INVALID = 0, - TASK_WAIT, - TASK_WAIT_FACE_ENEMY, - TASK_WAIT_PVS, - TASK_SUGGEST_STATE, - TASK_WALK_TO_TARGET, - TASK_RUN_TO_TARGET, - TASK_MOVE_TO_TARGET_RANGE, - TASK_GET_PATH_TO_ENEMY, - TASK_GET_PATH_TO_ENEMY_LKP, - TASK_GET_PATH_TO_ENEMY_CORPSE, - TASK_GET_PATH_TO_LEADER, - TASK_GET_PATH_TO_SPOT, - TASK_GET_PATH_TO_TARGET, - TASK_GET_PATH_TO_HINTNODE, - TASK_GET_PATH_TO_LASTPOSITION, - TASK_GET_PATH_TO_BESTSOUND, - TASK_GET_PATH_TO_BESTSCENT, - TASK_RUN_PATH, - TASK_WALK_PATH, - TASK_STRAFE_PATH, - TASK_CLEAR_MOVE_WAIT, - TASK_STORE_LASTPOSITION, - TASK_CLEAR_LASTPOSITION, - TASK_PLAY_ACTIVE_IDLE, - TASK_FIND_HINTNODE, - TASK_CLEAR_HINTNODE, - TASK_SMALL_FLINCH, - TASK_FACE_IDEAL, - TASK_FACE_ROUTE, - TASK_FACE_ENEMY, - TASK_FACE_HINTNODE, - TASK_FACE_TARGET, - TASK_FACE_LASTPOSITION, - TASK_RANGE_ATTACK1, - TASK_RANGE_ATTACK2, - TASK_MELEE_ATTACK1, - TASK_MELEE_ATTACK2, - TASK_RELOAD, - TASK_RANGE_ATTACK1_NOTURN, - TASK_RANGE_ATTACK2_NOTURN, - TASK_MELEE_ATTACK1_NOTURN, - TASK_MELEE_ATTACK2_NOTURN, - TASK_RELOAD_NOTURN, - TASK_SPECIAL_ATTACK1, - TASK_SPECIAL_ATTACK2, - TASK_CROUCH, - TASK_STAND, - TASK_GUARD, - TASK_STEP_LEFT, - TASK_STEP_RIGHT, - TASK_STEP_FORWARD, - TASK_STEP_BACK, - TASK_DODGE_LEFT, - TASK_DODGE_RIGHT, - TASK_SOUND_ANGRY, - TASK_SOUND_DEATH, - TASK_SET_ACTIVITY, - TASK_SET_SCHEDULE, - TASK_SET_FAIL_SCHEDULE, - TASK_CLEAR_FAIL_SCHEDULE, - TASK_PLAY_SEQUENCE, - TASK_PLAY_SEQUENCE_FACE_ENEMY, - TASK_PLAY_SEQUENCE_FACE_TARGET, - TASK_SOUND_IDLE, - TASK_SOUND_WAKE, - TASK_SOUND_PAIN, - TASK_SOUND_DIE, - TASK_FIND_COVER_FROM_BEST_SOUND,// tries lateral cover first, then node cover - TASK_FIND_COVER_FROM_ENEMY,// tries lateral cover first, then node cover - TASK_FIND_LATERAL_COVER_FROM_ENEMY, - TASK_FIND_NODE_COVER_FROM_ENEMY, - TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY,// data for this one is the MAXIMUM acceptable distance to the cover. - TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,// data for this one is there MINIMUM aceptable distance to the cover. - TASK_FIND_COVER_FROM_ORIGIN, - TASK_EAT, - TASK_DIE, - TASK_WAIT_FOR_SCRIPT, - TASK_PLAY_SCRIPT, - TASK_ENABLE_SCRIPT, - TASK_PLANT_ON_SCRIPT, - TASK_FACE_SCRIPT, - TASK_WAIT_RANDOM, - TASK_WAIT_INDEFINITE, - TASK_STOP_MOVING, - TASK_TURN_LEFT, - TASK_TURN_RIGHT, - TASK_REMEMBER, - TASK_FORGET, - TASK_WAIT_FOR_MOVEMENT, // wait until MovementIsComplete() - LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb) -} SHARED_TASKS; - - -// These go in the flData member of the TASK_WALK_TO_TARGET, TASK_RUN_TO_TARGET -enum -{ - TARGET_MOVE_NORMAL = 0, - TARGET_MOVE_SCRIPTED = 1, -}; - - -// A goal should be used for a task that requires several schedules to complete. -// The goal index should indicate which schedule (ordinally) the monster is running. -// That way, when tasks fail, the AI can make decisions based on the context of the -// current goal and sequence rather than just the current schedule. -enum -{ - GOAL_ATTACK_ENEMY, - GOAL_MOVE, - GOAL_TAKE_COVER, - GOAL_MOVE_TARGET, - GOAL_EAT, -}; - -// an array of tasks is a task list -// an array of schedules is a schedule list -struct Task_t -{ - - int iTask; - float flData; -}; - -struct Schedule_t -{ - - Task_t *pTasklist; - int cTasks; - int iInterruptMask;// a bit mask of conditions that can interrupt this schedule - - // a more specific mask that indicates which TYPES of sounds will interrupt the schedule in the - // event that the schedule is broken by COND_HEAR_SOUND - int iSoundMask; - const char *pName; -}; - -// an array of waypoints makes up the monster's route. -// !!!LATER- this declaration doesn't belong in this file. -struct WayPoint_t -{ - Vector vecLocation; - int iType; -}; - -// these MoveFlag values are assigned to a WayPoint's TYPE in order to demonstrate the -// type of movement the monster should use to get there. -#define bits_MF_TO_TARGETENT ( 1 << 0 ) // local move to targetent. -#define bits_MF_TO_ENEMY ( 1 << 1 ) // local move to enemy -#define bits_MF_TO_COVER ( 1 << 2 ) // local move to a hiding place -#define bits_MF_TO_DETOUR ( 1 << 3 ) // local move to detour point. -#define bits_MF_TO_PATHCORNER ( 1 << 4 ) // local move to a path corner -#define bits_MF_TO_NODE ( 1 << 5 ) // local move to a node -#define bits_MF_TO_LOCATION ( 1 << 6 ) // local move to an arbitrary point -#define bits_MF_IS_GOAL ( 1 << 7 ) // this waypoint is the goal of the whole move. -#define bits_MF_DONT_SIMPLIFY ( 1 << 8 ) // Don't let the route code simplify this waypoint - -// If you define any flags that aren't _TO_ flags, add them here so we can mask -// them off when doing compares. -#define bits_MF_NOT_TO_MASK (bits_MF_IS_GOAL | bits_MF_DONT_SIMPLIFY) - -#define MOVEGOAL_NONE (0) -#define MOVEGOAL_TARGETENT (bits_MF_TO_TARGETENT) -#define MOVEGOAL_ENEMY (bits_MF_TO_ENEMY) -#define MOVEGOAL_PATHCORNER (bits_MF_TO_PATHCORNER) -#define MOVEGOAL_LOCATION (bits_MF_TO_LOCATION) -#define MOVEGOAL_NODE (bits_MF_TO_NODE) - -// these bits represent conditions that may befall the monster, of which some are allowed -// to interrupt certain schedules. -#define bits_COND_NO_AMMO_LOADED ( 1 << 0 ) // weapon needs to be reloaded! -#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate -#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of -#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike -#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view. -#define bits_COND_ENEMY_OCCLUDED ( 1 << 5 ) // target entity occluded by the world -#define bits_COND_SMELL_FOOD ( 1 << 6 ) -#define bits_COND_ENEMY_TOOFAR ( 1 << 7 ) -#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little -#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot -#define bits_COND_CAN_RANGE_ATTACK1 ( 1 << 10) -#define bits_COND_CAN_MELEE_ATTACK1 ( 1 << 11) -#define bits_COND_CAN_RANGE_ATTACK2 ( 1 << 12) -#define bits_COND_CAN_MELEE_ATTACK2 ( 1 << 13) -// #define bits_COND_CAN_RANGE_ATTACK3 ( 1 << 14) -#define bits_COND_PROVOKED ( 1 << 15) -#define bits_COND_NEW_ENEMY ( 1 << 16) -#define bits_COND_HEAR_SOUND ( 1 << 17) // there is an interesting sound -#define bits_COND_SMELL ( 1 << 18) // there is an interesting scent -#define bits_COND_ENEMY_FACING_ME ( 1 << 19) // enemy is facing me -#define bits_COND_ENEMY_DEAD ( 1 << 20) // enemy was killed. If you get this in combat, try to find another enemy. If you get it in alert, victory dance. -#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client -#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis - -#define bits_COND_SPECIAL1 ( 1 << 28) // Defined by individual monster -#define bits_COND_SPECIAL2 ( 1 << 29) // Defined by individual monster - -#define bits_COND_TASK_FAILED ( 1 << 30) -#define bits_COND_SCHEDULE_DONE ( 1 << 31) - - -#define bits_COND_ALL_SPECIAL (bits_COND_SPECIAL1 | bits_COND_SPECIAL2) - -#define bits_COND_CAN_ATTACK (bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK2) - -#endif // SCHEDULE_H diff --git a/sdk/dlls/scientist.cpp b/sdk/dlls/scientist.cpp deleted file mode 100644 index cc60136..0000000 --- a/sdk/dlls/scientist.cpp +++ /dev/null @@ -1,1435 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// human scientist (passive lab worker) -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "talkmonster.h" -#include "schedule.h" -#include "defaultai.h" -#include "scripted.h" -#include "animation.h" -#include "soundent.h" - - -#define NUM_SCIENTIST_HEADS 4 // four heads available for scientist model -enum { HEAD_GLASSES = 0, HEAD_EINSTEIN = 1, HEAD_LUTHER = 2, HEAD_SLICK = 3 }; - -enum -{ - SCHED_HIDE = LAST_TALKMONSTER_SCHEDULE + 1, - SCHED_FEAR, - SCHED_PANIC, - SCHED_STARTLE, - SCHED_TARGET_CHASE_SCARED, - SCHED_TARGET_FACE_SCARED, -}; - -enum -{ - TASK_SAY_HEAL = LAST_TALKMONSTER_TASK + 1, - TASK_HEAL, - TASK_SAY_FEAR, - TASK_RUN_PATH_SCARED, - TASK_SCREAM, - TASK_RANDOM_SCREAM, - TASK_MOVE_TO_TARGET_RANGE_SCARED, -}; - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define SCIENTIST_AE_HEAL ( 1 ) -#define SCIENTIST_AE_NEEDLEON ( 2 ) -#define SCIENTIST_AE_NEEDLEOFF ( 3 ) - -//======================================================= -// Scientist -//======================================================= - -class CScientist : public CTalkMonster -{ -public: - void Spawn( void ); - void Precache( void ); - - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void RunTask( Task_t *pTask ); - void StartTask( Task_t *pTask ); - int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; } - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - virtual int FriendNumber( int arrayNumber ); - void SetActivity ( Activity newActivity ); - Activity GetStoppedActivity( void ); - int ISoundMask( void ); - void DeclineFollowing( void ); - - float CoverRadius( void ) { return 1200; } // Need more room for cover because scientists want to get far away! - BOOL DisregardEnemy( CBaseEntity *pEnemy ) { return !pEnemy->IsAlive() || (gpGlobals->time - m_fearTime) > 15; } - - BOOL CanHeal( void ); - void Heal( void ); - void Scream( void ); - - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); - - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); - - void Killed( entvars_t *pevAttacker, int iGib ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - CUSTOM_SCHEDULES; - -private: - float m_painTime; - float m_healTime; - float m_fearTime; -}; - -LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ); - -TYPEDESCRIPTION CScientist::m_SaveData[] = -{ - DEFINE_FIELD( CScientist, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_healTime, FIELD_TIME ), - DEFINE_FIELD( CScientist, m_fearTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CScientist, CTalkMonster ); - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -Task_t tlFollow[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_CANT_FOLLOW }, // If you fail, bail out of follow - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) -// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slFollow[] = -{ - { - tlFollow, - ARRAYSIZE ( tlFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "Follow" - }, -}; - -Task_t tlFollowScared[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE },// If you fail, follow normally - { TASK_MOVE_TO_TARGET_RANGE_SCARED,(float)128 }, // Move within 128 of target ent (client) -// { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE_SCARED }, -}; - -Schedule_t slFollowScared[] = -{ - { - tlFollowScared, - ARRAYSIZE ( tlFollowScared ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - bits_SOUND_DANGER, - "FollowScared" - }, -}; - -Task_t tlFaceTargetScared[] = -{ - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE_SCARED }, -}; - -Schedule_t slFaceTargetScared[] = -{ - { - tlFaceTargetScared, - ARRAYSIZE ( tlFaceTargetScared ), - bits_COND_HEAR_SOUND | - bits_COND_NEW_ENEMY, - bits_SOUND_DANGER, - "FaceTargetScared" - }, -}; - -Task_t tlStopFollowing[] = -{ - { TASK_CANT_FOLLOW, (float)0 }, -}; - -Schedule_t slStopFollowing[] = -{ - { - tlStopFollowing, - ARRAYSIZE ( tlStopFollowing ), - 0, - 0, - "StopFollowing" - }, -}; - - -Task_t tlHeal[] = -{ - { TASK_MOVE_TO_TARGET_RANGE,(float)50 }, // Move within 60 of target ent (client) - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_CHASE }, // If you fail, catch up with that guy! (change this to put syringe away and then chase) - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SAY_HEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_ARM }, // Whip out the needle - { TASK_HEAL, (float)0 }, // Put it in the player - { TASK_PLAY_SEQUENCE_FACE_TARGET, (float)ACT_DISARM }, // Put away the needle -}; - -Schedule_t slHeal[] = -{ - { - tlHeal, - ARRAYSIZE ( tlHeal ), - 0, // Don't interrupt or he'll end up running around with a needle all the time - 0, - "Heal" - }, -}; - - -Task_t tlFaceTarget[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_TARGET, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE }, -}; - -Schedule_t slFaceTarget[] = -{ - { - tlFaceTarget, - ARRAYSIZE ( tlFaceTarget ), - bits_COND_CLIENT_PUSH | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_COMBAT | - bits_SOUND_DANGER, - "FaceTarget" - }, -}; - - -Task_t tlSciPanic[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SCREAM, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_EXCITED }, // This is really fear-stricken excitement - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, -}; - -Schedule_t slSciPanic[] = -{ - { - tlSciPanic, - ARRAYSIZE ( tlSciPanic ), - 0, - 0, - "SciPanic" - }, -}; - - -Task_t tlIdleSciStand[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds. - { TASK_TLK_HEADRESET, (float)0 }, // reset head position -}; - -Schedule_t slIdleSciStand[] = -{ - { - tlIdleSciStand, - ARRAYSIZE ( tlIdleSciStand ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "IdleSciStand" - - }, -}; - - -Task_t tlScientistCover[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH_SCARED, (float)0 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_SET_SCHEDULE, (float)SCHED_HIDE }, -}; - -Schedule_t slScientistCover[] = -{ - { - tlScientistCover, - ARRAYSIZE ( tlScientistCover ), - bits_COND_NEW_ENEMY, - 0, - "ScientistCover" - }, -}; - - - -Task_t tlScientistHide[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_CROUCH }, - { TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE }, // FIXME: This looks lame - { TASK_WAIT_RANDOM, (float)10.0 }, -}; - -Schedule_t slScientistHide[] = -{ - { - tlScientistHide, - ARRAYSIZE ( tlScientistHide ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - bits_SOUND_DANGER, - "ScientistHide" - }, -}; - - -Task_t tlScientistStartle[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_PANIC }, // If you fail, just panic! - { TASK_RANDOM_SCREAM, (float)0.3 }, // Scream 30% of the time - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_RANDOM_SCREAM, (float)0.1 }, // Scream again 10% of the time - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCHIDLE }, - { TASK_WAIT_RANDOM, (float)1.0 }, -}; - -Schedule_t slScientistStartle[] = -{ - { - tlScientistStartle, - ARRAYSIZE ( tlScientistStartle ), - bits_COND_NEW_ENEMY | - bits_COND_SEE_ENEMY | - bits_COND_SEE_HATE | - bits_COND_SEE_FEAR | - bits_COND_SEE_DISLIKE, - 0, - "ScientistStartle" - }, -}; - - - -Task_t tlFear[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SAY_FEAR, (float)0 }, -// { TASK_PLAY_SEQUENCE, (float)ACT_FEAR_DISPLAY }, -}; - -Schedule_t slFear[] = -{ - { - tlFear, - ARRAYSIZE ( tlFear ), - bits_COND_NEW_ENEMY, - 0, - "Fear" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CScientist ) -{ - slFollow, - slFaceTarget, - slIdleSciStand, - slFear, - slScientistCover, - slScientistHide, - slScientistStartle, - slHeal, - slStopFollowing, - slSciPanic, - slFollowScared, - slFaceTargetScared, -}; - - -IMPLEMENT_CUSTOM_SCHEDULES( CScientist, CTalkMonster ); - - -void CScientist::DeclineFollowing( void ) -{ - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); -} - - -void CScientist :: Scream( void ) -{ - if ( FOkToSpeak() ) - { - Talk( 10 ); - m_hTalkTarget = m_hEnemy; - PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); - } -} - - -Activity CScientist::GetStoppedActivity( void ) -{ - if ( m_hEnemy != 0 ) - return ACT_EXCITED; - return CTalkMonster::GetStoppedActivity(); -} - - -void CScientist :: StartTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_SAY_HEAL: -// if ( FOkToSpeak() ) - Talk( 2 ); - m_hTalkTarget = m_hTargetEnt; - PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); - - TaskComplete(); - break; - - case TASK_SCREAM: - Scream(); - TaskComplete(); - break; - - case TASK_RANDOM_SCREAM: - if ( RANDOM_FLOAT( 0, 1 ) < pTask->flData ) - Scream(); - TaskComplete(); - break; - - case TASK_SAY_FEAR: - if ( FOkToSpeak() ) - { - Talk( 2 ); - m_hTalkTarget = m_hEnemy; - if ( m_hEnemy->IsPlayer() ) - PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); - else - PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); - } - TaskComplete(); - break; - - case TASK_HEAL: - m_IdealActivity = ACT_MELEE_ATTACK1; - break; - - case TASK_RUN_PATH_SCARED: - m_movementActivity = ACT_RUN_SCARED; - break; - - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if ( (m_hTargetEnt->pev->origin - pev->origin).Length() < 1 ) - TaskComplete(); - else - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - if ( !MoveToTarget( ACT_WALK_SCARED, 0.5 ) ) - TaskFail(); - } - } - break; - - default: - CTalkMonster::StartTask( pTask ); - break; - } -} - -void CScientist :: RunTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_RUN_PATH_SCARED: - if ( MovementIsComplete() ) - TaskComplete(); - if ( RANDOM_LONG(0,31) < 8 ) - Scream(); - break; - - case TASK_MOVE_TO_TARGET_RANGE_SCARED: - { - if ( RANDOM_LONG(0,63)< 8 ) - Scream(); - - if ( m_hEnemy == 0 ) - { - TaskFail(); - } - else - { - float distance; - - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - // Re-evaluate when you think your finished, or the target has moved too far - if ( (distance < pTask->flData) || (m_vecMoveGoal - m_hTargetEnt->pev->origin).Length() > pTask->flData * 0.5 ) - { - m_vecMoveGoal = m_hTargetEnt->pev->origin; - distance = ( m_vecMoveGoal - pev->origin ).Length2D(); - FRefreshRoute(); - } - - // Set the appropriate activity based on an overlapping range - // overlap the range to prevent oscillation - if ( distance < pTask->flData ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - else if ( distance < 190 && m_movementActivity != ACT_WALK_SCARED ) - m_movementActivity = ACT_WALK_SCARED; - else if ( distance >= 270 && m_movementActivity != ACT_RUN_SCARED ) - m_movementActivity = ACT_RUN_SCARED; - } - } - break; - - case TASK_HEAL: - if ( m_fSequenceFinished ) - { - TaskComplete(); - } - else - { - if ( TargetDistance() > 90 ) - TaskComplete(); - pev->ideal_yaw = UTIL_VecToYaw( m_hTargetEnt->pev->origin - pev->origin ); - ChangeYaw( pev->yaw_speed ); - } - break; - default: - CTalkMonster::RunTask( pTask ); - break; - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CScientist :: Classify ( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CScientist :: SetYawSpeed ( void ) -{ - int ys; - - ys = 90; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 120; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 120; - break; - default: - break; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CScientist :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCIENTIST_AE_HEAL: // Heal my target (if within range) - Heal(); - break; - case SCIENTIST_AE_NEEDLEON: - { - int oldBody = pev->body; - pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 1; - } - break; - case SCIENTIST_AE_NEEDLEOFF: - { - int oldBody = pev->body; - pev->body = (oldBody % NUM_SCIENTIST_HEADS) + NUM_SCIENTIST_HEADS * 0; - } - break; - - default: - CTalkMonster::HandleAnimEvent( pEvent ); - } -} - -//========================================================= -// Spawn -//========================================================= -void CScientist :: Spawn( void ) -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/scientist.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_RED; - pev->health = gSkillData.scientistHealth; - pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin. - m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so scientists will notice player and say hello - m_MonsterState = MONSTERSTATE_NONE; - -// m_flDistTooFar = 256.0; - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE; - - // White hands - pev->skin = 0; - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - MonsterInit(); - SetUse( &CScientist::FollowerUse ); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CScientist :: Precache( void ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - PRECACHE_SOUND("scientist/sci_pain1.wav"); - PRECACHE_SOUND("scientist/sci_pain2.wav"); - PRECACHE_SOUND("scientist/sci_pain3.wav"); - PRECACHE_SOUND("scientist/sci_pain4.wav"); - PRECACHE_SOUND("scientist/sci_pain5.wav"); - - // every new scientist must call this, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - TalkInit(); - - CTalkMonster::Precache(); -} - -// Init talk data -void CScientist :: TalkInit() -{ - - CTalkMonster::TalkInit(); - - // scientist will try to talk to friends in this order: - - m_szFriends[0] = "monster_scientist"; - m_szFriends[1] = "monster_sitting_scientist"; - m_szFriends[2] = "monster_barney"; - - // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "SC_ANSWER"; - m_szGrp[TLK_QUESTION] = "SC_QUESTION"; - m_szGrp[TLK_IDLE] = "SC_IDLE"; - m_szGrp[TLK_STARE] = "SC_STARE"; - m_szGrp[TLK_USE] = "SC_OK"; - m_szGrp[TLK_UNUSE] = "SC_WAIT"; - m_szGrp[TLK_STOP] = "SC_STOP"; - m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; - m_szGrp[TLK_HELLO] = "SC_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; - m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; - m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; - - m_szGrp[TLK_PHELLO] = "SC_PHELLO"; - m_szGrp[TLK_PIDLE] = "SC_PIDLE"; - m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; - m_szGrp[TLK_SMELL] = "SC_SMELL"; - - m_szGrp[TLK_WOUND] = "SC_WOUND"; - m_szGrp[TLK_MORTAL] = "SC_MORTAL"; - - // get voice for head - switch (pev->body % 3) - { - default: - case HEAD_GLASSES: m_voicePitch = 105; break; //glasses - case HEAD_EINSTEIN: m_voicePitch = 100; break; //einstein - case HEAD_LUTHER: m_voicePitch = 95; break; //luther - case HEAD_SLICK: m_voicePitch = 100; break;//slick - } -} - -int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - - if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) - { - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } - - // make sure friends talk about it if player hurts scientist... - return CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -//========================================================= -// ISoundMask - returns a bit mask indicating which types -// of sounds this monster regards. In the base class implementation, -// monsters care about all sounds, but no scents. -//========================================================= -int CScientist :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_DANGER | - bits_SOUND_PLAYER; -} - -//========================================================= -// PainSound -//========================================================= -void CScientist :: PainSound ( void ) -{ - if (gpGlobals->time < m_painTime ) - return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - - switch (RANDOM_LONG(0,4)) - { - case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 3: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain4.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - case 4: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain5.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CScientist :: DeathSound ( void ) -{ - PainSound(); -} - - -void CScientist::Killed( entvars_t *pevAttacker, int iGib ) -{ - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); -} - - -void CScientist :: SetActivity ( Activity newActivity ) -{ - int iSequence; - - iSequence = LookupActivity ( newActivity ); - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence == ACTIVITY_NOT_AVAILABLE ) - newActivity = ACT_IDLE; - CTalkMonster::SetActivity( newActivity ); -} - - -Schedule_t* CScientist :: GetScheduleOfType ( int Type ) -{ - Schedule_t *psched; - - switch( Type ) - { - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that scientist will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slFaceTarget; // override this for different target face behavior - else - return psched; - - case SCHED_TARGET_CHASE: - return slFollow; - - case SCHED_CANT_FOLLOW: - return slStopFollowing; - - case SCHED_PANIC: - return slSciPanic; - - case SCHED_TARGET_CHASE_SCARED: - return slFollowScared; - - case SCHED_TARGET_FACE_SCARED: - return slFaceTargetScared; - - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slIdleSciStand; - else - return psched; - - case SCHED_HIDE: - return slScientistHide; - - case SCHED_STARTLE: - return slScientistStartle; - - case SCHED_FEAR: - return slFear; - } - - return CTalkMonster::GetScheduleOfType( Type ); -} - -Schedule_t *CScientist :: GetSchedule ( void ) -{ - // so we don't keep calling through the EHANDLE stuff - CBaseEntity *pEnemy = m_hEnemy; - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) ) - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - - switch( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( pEnemy ) - { - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - m_fearTime = gpGlobals->time; - else if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - m_hEnemy = NULL; - pEnemy = NULL; - } - } - - if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE)) - { - // flinch if hurt - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - - // Cower when you hear something scary - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound ) - { - if ( pSound->m_iType & (bits_SOUND_DANGER | bits_SOUND_COMBAT) ) - { - if ( gpGlobals->time - m_fearTime > 3 ) // Only cower every 3 seconds or so - { - m_fearTime = gpGlobals->time; // Update last fear - return GetScheduleOfType( SCHED_STARTLE ); // This will just duck for a second - } - } - } - } - - // Behavior for following the player - if ( IsFollowing() ) - { - if ( !m_hTargetEnt->IsAlive() ) - { - // UNDONE: Comment about the recently dead player here? - StopFollowing( FALSE ); - break; - } - - int relationship = R_NO; - - // Nothing scary, just me and the player - if ( pEnemy != NULL ) - relationship = IRelationship( pEnemy ); - - // UNDONE: Model fear properly, fix R_FR and add multiple levels of fear - if ( relationship != R_DL && relationship != R_HT ) - { - // If I'm already close enough to my target - if ( TargetDistance() <= 128 ) - { - if ( CanHeal() ) // Heal opportunistically - return slHeal; - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); - } - return GetScheduleOfType( SCHED_TARGET_FACE ); // Just face and follow. - } - else // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared - { - if ( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react - return GetScheduleOfType( SCHED_FEAR ); // React to something scary - return GetScheduleOfType( SCHED_TARGET_FACE_SCARED ); // face and follow, but I'm scared! - } - } - - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) // Player wants me to move - return GetScheduleOfType( SCHED_MOVE_AWAY ); - - // try to say something about smells - TrySmellTalk(); - break; - case MONSTERSTATE_COMBAT: - if ( HasConditions( bits_COND_NEW_ENEMY ) ) - return slFear; // Point and scream! - if ( HasConditions( bits_COND_SEE_ENEMY ) ) - return slScientistCover; // Take Cover - - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - return slTakeCoverFromBestSound; // Cower and panic from the scary sound! - - return slScientistCover; // Run & Cower - break; - default: - break; - } - - return CTalkMonster::GetSchedule(); -} - -MONSTERSTATE CScientist :: GetIdealState ( void ) -{ - switch ( m_MonsterState ) - { - case MONSTERSTATE_ALERT: - case MONSTERSTATE_IDLE: - if ( HasConditions( bits_COND_NEW_ENEMY ) ) - { - if ( IsFollowing() ) - { - int relationship = IRelationship( m_hEnemy ); - if ( relationship != R_FR || (relationship != R_HT && !HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE )) ) - { - // Don't go to combat if you're following the player - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - StopFollowing( TRUE ); - } - } - else if ( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) ) - { - // Stop following if you take damage - if ( IsFollowing() ) - StopFollowing( TRUE ); - } - break; - - case MONSTERSTATE_COMBAT: - { - CBaseEntity *pEnemy = m_hEnemy; - if ( pEnemy != NULL ) - { - if ( DisregardEnemy( pEnemy ) ) // After 15 seconds of being hidden, return to alert - { - // Strip enemy when going to alert - m_IdealMonsterState = MONSTERSTATE_ALERT; - m_hEnemy = 0; - return m_IdealMonsterState; - } - // Follow if only scared a little - if ( m_hTargetEnt != 0 ) - { - m_IdealMonsterState = MONSTERSTATE_ALERT; - return m_IdealMonsterState; - } - - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - m_fearTime = gpGlobals->time; - m_IdealMonsterState = MONSTERSTATE_COMBAT; - return m_IdealMonsterState; - } - - } - } - break; - - default: - break; - } - - return CTalkMonster::GetIdealState(); -} - - -BOOL CScientist::CanHeal( void ) -{ - if ( (m_healTime > gpGlobals->time) || (m_hTargetEnt == 0) || (m_hTargetEnt->pev->health > (m_hTargetEnt->pev->max_health * 0.5)) ) - return FALSE; - - return TRUE; -} - -void CScientist::Heal( void ) -{ - if ( !CanHeal() ) - return; - - Vector target = m_hTargetEnt->pev->origin - pev->origin; - if ( target.Length() > 100 ) - return; - - m_hTargetEnt->TakeHealth( gSkillData.scientistHeal, DMG_GENERIC ); - // Don't heal again for 1 minute - m_healTime = gpGlobals->time + 60; -} - -int CScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 1, 2, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; - return arrayNumber; -} - - -//========================================================= -// Dead Scientist PROP -//========================================================= -class CDeadScientist : public CBaseMonster -{ -public: - void Spawn( void ); - int Classify ( void ) { return CLASS_HUMAN_PASSIVE; } - - void KeyValue( KeyValueData *pkvd ); - int m_iPose;// which sequence to display - static const char *m_szPoses[7]; -}; -const char *CDeadScientist::m_szPoses[] = { "lying_on_back", "lying_on_stomach", "dead_sitting", "dead_hang", "dead_table1", "dead_table2", "dead_table3" }; - -void CDeadScientist::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "pose")) - { - m_iPose = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} -LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist ); - -// -// ********** DeadScientist SPAWN ********** -// -void CDeadScientist :: Spawn( ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - - pev->effects = 0; - pev->sequence = 0; - // Corpses have less health - pev->health = 8;//gSkillData.scientistHealth; - - m_bloodColor = BLOOD_COLOR_RED; - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - else - pev->skin = 0; - - pev->sequence = LookupSequence( m_szPoses[m_iPose] ); - if (pev->sequence == -1) - { - ALERT ( at_console, "Dead scientist with bad pose\n" ); - } - - // pev->skin += 2; // use bloody skin -- UNDONE: Turn this back on when we have a bloody skin again! - MonsterInitDead(); -} - - -//========================================================= -// Sitting Scientist PROP -//========================================================= - -class CSittingScientist : public CScientist // kdb: changed from public CBaseMonster so he can speak -{ -public: - void Spawn( void ); - void Precache( void ); - - void EXPORT SittingThink( void ); - int Classify ( void ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); - int FriendNumber( int arrayNumber ); - - int FIdleSpeak ( void ); - int m_baseSequence; - int m_headTurn; - float m_flResponseDelay; -}; - -LINK_ENTITY_TO_CLASS( monster_sitting_scientist, CSittingScientist ); -TYPEDESCRIPTION CSittingScientist::m_SaveData[] = -{ - // Don't need to save/restore m_baseSequence (recalced) - DEFINE_FIELD( CSittingScientist, m_headTurn, FIELD_INTEGER ), - DEFINE_FIELD( CSittingScientist, m_flResponseDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CSittingScientist, CScientist ); - -// animation sequence aliases -typedef enum -{ -SITTING_ANIM_sitlookleft, -SITTING_ANIM_sitlookright, -SITTING_ANIM_sitscared, -SITTING_ANIM_sitting2, -SITTING_ANIM_sitting3 -} SITTING_ANIM; - - -// -// ********** Scientist SPAWN ********** -// -void CSittingScientist :: Spawn( ) -{ - PRECACHE_MODEL("models/scientist.mdl"); - SET_MODEL(ENT(pev), "models/scientist.mdl"); - Precache(); - InitBoneControllers(); - - UTIL_SetSize(pev, Vector(-14, -14, 0), Vector(14, 14, 36)); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 50; - - m_bloodColor = BLOOD_COLOR_RED; - m_flFieldOfView = VIEW_FIELD_WIDE; // indicates the width of this monster's forward view cone ( as a dotproduct result ) - - m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD; - - SetBits(pev->spawnflags, SF_MONSTER_PREDISASTER); // predisaster only! - - if ( pev->body == -1 ) - {// -1 chooses a random head - pev->body = RANDOM_LONG(0, NUM_SCIENTIST_HEADS-1);// pick a head, any head - } - // Luther is black, make his hands black - if ( pev->body == HEAD_LUTHER ) - pev->skin = 1; - - m_baseSequence = LookupSequence( "sitlookleft" ); - pev->sequence = m_baseSequence + RANDOM_LONG(0,4); - ResetSequenceInfo( ); - - SetThink (&CSittingScientist::SittingThink); - pev->nextthink = gpGlobals->time + 0.1; - - DROP_TO_FLOOR ( ENT(pev) ); -} - -void CSittingScientist :: Precache( void ) -{ - m_baseSequence = LookupSequence( "sitlookleft" ); - TalkInit(); -} - -//========================================================= -// ID as a passive human -//========================================================= -int CSittingScientist :: Classify ( void ) -{ - return CLASS_HUMAN_PASSIVE; -} - - -int CSittingScientist::FriendNumber( int arrayNumber ) -{ - static int array[3] = { 2, 1, 0 }; - if ( arrayNumber < 3 ) - return array[ arrayNumber ]; - return arrayNumber; -} - - - -//========================================================= -// sit, do stuff -//========================================================= -void CSittingScientist :: SittingThink( void ) -{ - CBaseEntity *pent; - - StudioFrameAdvance( ); - - // try to greet player - if (FIdleHello()) - { - pent = FindNearestFriend(TRUE); - if (pent) - { - float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - ResetSequenceInfo( ); - pev->frame = 0; - SetBoneController( 0, 0 ); - } - } - else if (m_fSequenceFinished) - { - int i = RANDOM_LONG(0,99); - m_headTurn = 0; - - if (m_flResponseDelay && gpGlobals->time > m_flResponseDelay) - { - // respond to question - IdleRespond(); - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - m_flResponseDelay = 0; - } - else if (i < 30) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - - // turn towards player or nearest friend and speak - - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - pent = FindNearestFriend(TRUE); - else - pent = FindNearestFriend(FALSE); - - if (!FIdleSpeak() || !pent) - { - m_headTurn = RANDOM_LONG(0,8) * 10 - 40; - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - } - else - { - // only turn head if we spoke - float yaw = VecToYaw(pent->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw > 0) - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookleft; - else - pev->sequence = m_baseSequence + SITTING_ANIM_sitlookright; - - //ALERT(at_console, "sitting speak\n"); - } - } - else if (i < 60) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting3; - m_headTurn = RANDOM_LONG(0,8) * 10 - 40; - if (RANDOM_LONG(0,99) < 5) - { - //ALERT(at_console, "sitting speak2\n"); - FIdleSpeak(); - } - } - else if (i < 80) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitting2; - } - else if (i < 100) - { - pev->sequence = m_baseSequence + SITTING_ANIM_sitscared; - } - - ResetSequenceInfo( ); - pev->frame = 0; - SetBoneController( 0, m_headTurn ); - } - pev->nextthink = gpGlobals->time + 0.1; -} - -// prepare sitting scientist to answer a question -void CSittingScientist :: SetAnswerQuestion( CTalkMonster *pSpeaker ) -{ - m_flResponseDelay = gpGlobals->time + RANDOM_FLOAT(3, 4); - m_hTalkTarget = (CBaseMonster *)pSpeaker; -} - - -//========================================================= -// FIdleSpeak -// ask question of nearby friend, or make statement -//========================================================= -int CSittingScientist :: FIdleSpeak ( void ) -{ - // try to start a conversation, or make statement - int pitch; - - if (!FOkToSpeak()) - return FALSE; - - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - - pitch = GetVoicePitch(); - - // if there is a friend nearby to speak to, play sentence, set friend's response time, return - - // try to talk to any standing or sitting scientists nearby - CBaseEntity *pentFriend = FindNearestFriend(FALSE); - - if (pentFriend && RANDOM_LONG(0,1)) - { - CTalkMonster *pTalkMonster = GetClassPtr((CTalkMonster *)pentFriend->pev); - pTalkMonster->SetAnswerQuestion( this ); - - IdleHeadTurn(pentFriend->pev->origin); - SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PQUESTION], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - return TRUE; - } - - // otherwise, play an idle statement - if (RANDOM_LONG(0,1)) - { - SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_PIDLE], 1.0, ATTN_IDLE, 0, pitch ); - // set global min delay for next conversation - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(4.8, 5.2); - return TRUE; - } - - // never spoke - CTalkMonster::g_talkWaitTime = 0; - return FALSE; -} diff --git a/sdk/dlls/scripted.cpp b/sdk/dlls/scripted.cpp deleted file mode 100644 index f008285..0000000 --- a/sdk/dlls/scripted.cpp +++ /dev/null @@ -1,1260 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - - -===== scripted.cpp ======================================================== - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" - -#ifndef ANIMATION_H -#include "animation.h" -#endif - -#ifndef SAVERESTORE_H -#include "saverestore.h" -#endif - -#include "schedule.h" -#include "scripted.h" -#include "defaultai.h" - - - -/* -classname "scripted_sequence" -targetname "me" - there can be more than one with the same name, and they act in concert -target "the_entity_I_want_to_start_playing" or "class entity_classname" will pick the closest inactive scientist -play "name_of_sequence" -idle "name of idle sequence to play before starting" -donetrigger "whatever" - can be any other triggerable entity such as another sequence, train, door, or a special case like "die" or "remove" -moveto - if set the monster first moves to this nodes position -range # - only search this far to find the target -spawnflags - (stop if blocked, stop if player seen) -*/ - - -// -// Cache user-entity-field values until spawn is called. -// - -void CCineMonster :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszIdle")) - { - m_iszIdle = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszPlay")) - { - m_iszPlay = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iszEntity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_fMoveTo")) - { - m_fMoveTo = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRepeat")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_flRadius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "m_iFinishSchedule")) - { - m_iFinishSchedule = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - { - CBaseMonster::KeyValue( pkvd ); - } -} - -TYPEDESCRIPTION CCineMonster::m_SaveData[] = -{ - DEFINE_FIELD( CCineMonster, m_iszIdle, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszPlay, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CCineMonster, m_fMoveTo, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CCineMonster, m_flRadius, FIELD_FLOAT ), - - DEFINE_FIELD( CCineMonster, m_iDelay, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_startTime, FIELD_TIME ), - - DEFINE_FIELD( CCineMonster, m_saved_movetype, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_solid, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_saved_effects, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_iFinishSchedule, FIELD_INTEGER ), - DEFINE_FIELD( CCineMonster, m_interruptable, FIELD_BOOLEAN ), -}; - - -IMPLEMENT_SAVERESTORE( CCineMonster, CBaseMonster ); - -LINK_ENTITY_TO_CLASS( scripted_sequence, CCineMonster ); -#define CLASSNAME "scripted_sequence" - -LINK_ENTITY_TO_CLASS( aiscripted_sequence, CCineAI ); - - -void CCineMonster :: Spawn( void ) -{ - // pev->solid = SOLID_TRIGGER; - // UTIL_SetSize(pev, Vector(-8, -8, -8), Vector(8, 8, 8)); - pev->solid = SOLID_NOT; - - - // REMOVE: The old side-effect -#if 0 - if ( m_iszIdle ) - m_fMoveTo = 4; -#endif - - // if no targetname, start now - if ( FStringNull(pev->targetname) || !FStringNull( m_iszIdle ) ) - { - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time + 1.0; - // Wait to be used? - if ( pev->targetname ) - m_startTime = gpGlobals->time + 1E6; - } - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - m_interruptable = FALSE; - else - m_interruptable = TRUE; -} - -//========================================================= -// FCanOverrideState - returns FALSE, scripted sequences -// cannot possess entities regardless of state. -//========================================================= -BOOL CCineMonster :: FCanOverrideState( void ) -{ - if ( pev->spawnflags & SF_SCRIPT_OVERRIDESTATE ) - return TRUE; - return FALSE; -} - -//========================================================= -// FCanOverrideState - returns true because scripted AI can -// possess entities regardless of their state. -//========================================================= -BOOL CCineAI :: FCanOverrideState( void ) -{ - return TRUE; -} - - -// -// CineStart -// -void CCineMonster :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // do I already know who I should use - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - // am I already playing the script? - if ( pTarget->m_scriptState == SCRIPT_PLAYING ) - return; - - m_startTime = gpGlobals->time + 0.05; - } - else - { - // if not, try finding them - SetThink( &CCineMonster::CineThink ); - pev->nextthink = gpGlobals->time; - } -} - - -// This doesn't really make sense since only MOVETYPE_PUSH get 'Blocked' events -void CCineMonster :: Blocked( CBaseEntity *pOther ) -{ - -} - -void CCineMonster :: Touch( CBaseEntity *pOther ) -{ -/* - ALERT( at_aiconsole, "Cine Touch\n" ); - if (m_pentTarget && OFFSET(pOther->pev) == OFFSET(m_pentTarget)) - { - CBaseMonster *pTarget = GetClassPtr((CBaseMonster *)VARS(m_pentTarget)); - pTarget->m_monsterState == MONSTERSTATE_SCRIPT; - } -*/ -} - - -/* - entvars_t *pevOther = VARS( gpGlobals->other ); - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags -= FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - - - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE -} -*/ - - -// -// ********** Cinematic DIE ********** -// -void CCineMonster :: Die( void ) -{ - SetThink( &CCineMonster::SUB_Remove ); -} - -// -// ********** Cinematic PAIN ********** -// -void CCineMonster :: Pain( void ) -{ - -} - -// -// ********** Cinematic Think ********** -// - -// find a viable entity -int CCineMonster :: FindEntity( void ) -{ - edict_t *pentTarget; - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - m_hTargetEnt = NULL; - CBaseMonster *pTarget = NULL; - - while (!FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_BY_NAME ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - ALERT( at_console, "Found %s, but can't play!\n", STRING(m_iszEntity) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - pTarget = NULL; - } - - if ( !pTarget ) - { - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pTarget = pEntity->MyMonsterPointer( ); - if ( pTarget && pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_IDLE ) ) - { - m_hTargetEnt = pTarget; - return TRUE; - } - } - } - } - } - pTarget = NULL; - m_hTargetEnt = NULL; - return FALSE; -} - -// make the entity enter a scripted sequence -void CCineMonster :: PossessEntity( void ) -{ - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - - // FindEntity() just checked this! -#if 0 - if ( !pTarget->CanPlaySequence( FCanOverrideState() ) ) - { - ALERT( at_aiconsole, "Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } -#endif - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - DelayStart( 1 ); - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - DelayStart( 1 ); - break; - - case 4: - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - // pTarget->pev->flags &= ~FL_ONGROUND; - break; - } -// ALERT( at_aiconsole, "\"%s\" found and used (INT: %s)\n", STRING( pTarget->pev->targetname ), FBitSet(pev->spawnflags, SF_SCRIPT_NOINTERRUPT)?"No":"Yes" ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } - } -} - -// make the entity carry out the scripted sequence instructions, but without -// destroying the monster's state. -void CCineAI :: PossessEntity( void ) -{ - Schedule_t *pNewSchedule; - - CBaseEntity *pEntity = m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if ( pTarget ) - { - if ( !pTarget->CanPlaySequence( FCanOverrideState(), SS_INTERRUPT_AI ) ) - { - ALERT( at_aiconsole, "(AI)Can't possess entity %s\n", STRING(pTarget->pev->classname) ); - return; - } - - pTarget->m_pGoalEnt = this; - pTarget->m_pCine = this; - pTarget->m_hTargetEnt = this; - - m_saved_movetype = pTarget->pev->movetype; - m_saved_solid = pTarget->pev->solid; - m_saved_effects = pTarget->pev->effects; - pTarget->pev->effects |= pev->effects; - - switch (m_fMoveTo) - { - case 0: - case 5: - pTarget->m_scriptState = SCRIPT_WAIT; - break; - - case 1: - pTarget->m_scriptState = SCRIPT_WALK_TO_MARK; - break; - - case 2: - pTarget->m_scriptState = SCRIPT_RUN_TO_MARK; - break; - - case 4: - // zap the monster instantly to the site of the script entity. - UTIL_SetOrigin( pTarget->pev, pev->origin ); - pTarget->pev->ideal_yaw = pev->angles.y; - pTarget->pev->avelocity = Vector( 0, 0, 0 ); - pTarget->pev->velocity = Vector( 0, 0, 0 ); - pTarget->pev->effects |= EF_NOINTERP; - pTarget->pev->angles.y = pev->angles.y; - pTarget->m_scriptState = SCRIPT_WAIT; - m_startTime = gpGlobals->time + 1E6; - // UNDONE: Add a flag to do this so people can fixup physics after teleporting monsters - pTarget->pev->flags &= ~FL_ONGROUND; - break; - default: - ALERT ( at_aiconsole, "aiscript: invalid Move To Position value!" ); - break; - } - - ALERT( at_aiconsole, "\"%s\" found and used\n", STRING( pTarget->pev->targetname ) ); - - pTarget->m_IdealMonsterState = MONSTERSTATE_SCRIPT; - -/* - if (m_iszIdle) - { - StartSequence( pTarget, m_iszIdle, FALSE ); - if (FStrEq( STRING(m_iszIdle), STRING(m_iszPlay))) - { - pTarget->pev->framerate = 0; - } - } -*/ - // Already in a scripted state? - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - pNewSchedule = pTarget->GetScheduleOfType( SCHED_AISCRIPT ); - pTarget->ChangeSchedule( pNewSchedule ); - } - } -} - -void CCineMonster :: CineThink( void ) -{ - if (FindEntity()) - { - PossessEntity( ); - ALERT( at_aiconsole, "script \"%s\" using monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - } - else - { - CancelScript( ); - ALERT( at_aiconsole, "script \"%s\" can't find monster \"%s\"\n", STRING( pev->targetname ), STRING( m_iszEntity ) ); - pev->nextthink = gpGlobals->time + 1.0; - } -} - - -// lookup a sequence name and setup the target monster to play it -BOOL CCineMonster :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( !iszSeq && completeOnEmpty ) - { - SequenceDone( pTarget ); - return FALSE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown scripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - -#if 0 - char *s; - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - s = "No"; - else - s = "Yes"; - - ALERT( at_console, "%s (%s): started \"%s\":INT:%s\n", STRING( pTarget->pev->targetname ), STRING( pTarget->pev->classname ), STRING( iszSeq), s ); -#endif - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -// lookup a sequence name and setup the target monster to play it -// overridden for CCineAI because it's ok for them to not have an animation sequence -// for the monster to play. For a regular Scripted Sequence, that situation is an error. -BOOL CCineAI :: StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ) -{ - if ( iszSeq == 0 && completeOnEmpty ) - { - // no sequence was provided. Just let the monster proceed, however, we still have to fire any Sequence target - // and remove any non-repeatable CineAI entities here ( because there is code elsewhere that handles those tasks, but - // not until the animation sequence is finished. We have to manually take care of these things where there is no sequence. - - SequenceDone ( pTarget ); - - return TRUE; - } - - pTarget->pev->sequence = pTarget->LookupSequence( STRING( iszSeq ) ); - - if (pTarget->pev->sequence == -1) - { - ALERT( at_error, "%s: unknown aiscripted sequence \"%s\"\n", STRING( pTarget->pev->targetname ), STRING( iszSeq) ); - pTarget->pev->sequence = 0; - // return FALSE; - } - - pTarget->pev->frame = 0; - pTarget->ResetSequenceInfo( ); - return TRUE; -} - -//========================================================= -// SequenceDone - called when a scripted sequence animation -// sequence is done playing ( or when an AI Scripted Sequence -// doesn't supply an animation sequence to play ). Expects -// the CBaseMonster pointer to the monster that the sequence -// possesses. -//========================================================= -void CCineMonster :: SequenceDone ( CBaseMonster *pMonster ) -{ - //ALERT( at_aiconsole, "Sequence %s finished\n", STRING( m_pCine->m_iszPlay ) ); - - if ( !( pev->spawnflags & SF_SCRIPT_REPEATABLE ) ) - { - SetThink( &CCineMonster::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - } - - // This is done so that another sequence can take over the monster when triggered by the first - - pMonster->CineCleanup(); - - FixScriptMonsterSchedule( pMonster ); - - // This may cause a sequence to attempt to grab this guy NOW, so we have to clear him out - // of the existing sequence - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// Scripted sequences just dirty the Schedule and drop the -// monster in Idle State. -//========================================================= -void CCineMonster :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - if ( pMonster->m_IdealMonsterState != MONSTERSTATE_DEAD ) - pMonster->m_IdealMonsterState = MONSTERSTATE_IDLE; - pMonster->ClearSchedule(); -} - -//========================================================= -// When a monster finishes a scripted sequence, we have to -// fix up its state and schedule for it to return to a -// normal AI monster. -// -// AI Scripted sequences will, depending on what the level -// designer selects: -// -// -Dirty the monster's schedule and drop out of the -// sequence in their current state. -// -// -Select a specific AMBUSH schedule, regardless of state. -//========================================================= -void CCineAI :: FixScriptMonsterSchedule( CBaseMonster *pMonster ) -{ - switch ( m_iFinishSchedule ) - { - case SCRIPT_FINISHSCHED_DEFAULT: - pMonster->ClearSchedule(); - break; - case SCRIPT_FINISHSCHED_AMBUSH: - pMonster->ChangeSchedule( pMonster->GetScheduleOfType( SCHED_AMBUSH ) ); - break; - default: - ALERT ( at_aiconsole, "FixScriptMonsterSchedule - no case!\n" ); - pMonster->ClearSchedule(); - break; - } -} - -BOOL CBaseMonster :: ExitScriptedSequence( ) -{ - if ( pev->deadflag == DEAD_DYING ) - { - // is this legal? - // BUGBUG -- This doesn't call Killed() - m_IdealMonsterState = MONSTERSTATE_DEAD; - return FALSE; - } - - if (m_pCine) - { - m_pCine->CancelScript( ); - } - - return TRUE; -} - - -void CCineMonster::AllowInterrupt( BOOL fAllow ) -{ - if ( pev->spawnflags & SF_SCRIPT_NOINTERRUPT ) - return; - m_interruptable = fAllow; -} - - -BOOL CCineMonster::CanInterrupt( void ) -{ - if ( !m_interruptable ) - return FALSE; - - CBaseEntity *pTarget = m_hTargetEnt; - - if ( pTarget != NULL && pTarget->pev->deadflag == DEAD_NO ) - return TRUE; - - return FALSE; -} - - -int CCineMonster::IgnoreConditions( void ) -{ - if ( CanInterrupt() ) - return 0; - return SCRIPT_BREAK_CONDITIONS; -} - - -void ScriptEntityCancel( edict_t *pentCine ) -{ - // make sure they are a scripted_sequence - if (FClassnameIs( pentCine, CLASSNAME )) - { - CCineMonster *pCineTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - // make sure they have a monster in mind for the script - CBaseEntity *pEntity = pCineTarget->m_hTargetEnt; - CBaseMonster *pTarget = NULL; - if ( pEntity ) - pTarget = pEntity->MyMonsterPointer(); - - if (pTarget) - { - // make sure their monster is actually playing a script - if ( pTarget->m_MonsterState == MONSTERSTATE_SCRIPT ) - { - // tell them do die - pTarget->m_scriptState = CCineMonster::SCRIPT_CLEANUP; - // do it now - pTarget->CineCleanup( ); - } - } - } -} - - -// find all the cinematic entities with my targetname and stop them from playing -void CCineMonster :: CancelScript( void ) -{ - ALERT( at_aiconsole, "Cancelling script: %s\n", STRING(m_iszPlay) ); - - if ( !pev->targetname ) - { - ScriptEntityCancel( edict() ); - return; - } - - edict_t *pentCineTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCineTarget)) - { - ScriptEntityCancel( pentCineTarget ); - pentCineTarget = FIND_ENTITY_BY_TARGETNAME(pentCineTarget, STRING(pev->targetname)); - } -} - - -// find all the cinematic entities with my targetname and tell them to wait before starting -void CCineMonster :: DelayStart( int state ) -{ - edict_t *pentCine = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->targetname)); - - while (!FNullEnt(pentCine)) - { - if (FClassnameIs( pentCine, "scripted_sequence" )) - { - CCineMonster *pTarget = GetClassPtr((CCineMonster *)VARS(pentCine)); - if (state) - { - pTarget->m_iDelay++; - } - else - { - pTarget->m_iDelay--; - if (pTarget->m_iDelay <= 0) - pTarget->m_startTime = gpGlobals->time + 0.05; - } - } - pentCine = FIND_ENTITY_BY_TARGETNAME(pentCine, STRING(pev->targetname)); - } -} - - - -// Find an entity that I'm interested in and precache the sounds he'll need in the sequence. -void CCineMonster :: Activate( void ) -{ - edict_t *pentTarget; - CBaseMonster *pTarget; - - // The entity name could be a target name or a classname - // Check the targetname - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pTarget = NULL; - - while (!pTarget && !FNullEnt(pentTarget)) - { - if ( FBitSet( VARS(pentTarget)->flags, FL_MONSTER )) - { - pTarget = GetMonsterPointer( pentTarget ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - // If no entity with that targetname, check the classname - if ( !pTarget ) - { - pentTarget = FIND_ENTITY_BY_CLASSNAME(NULL, STRING(m_iszEntity)); - while (!pTarget && !FNullEnt(pentTarget)) - { - pTarget = GetMonsterPointer( pentTarget ); - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - } - // Found a compatible entity - if ( pTarget ) - { - void *pmodel; - pmodel = GET_MODEL_PTR( pTarget->edict() ); - if ( pmodel ) - { - // Look through the event list for stuff to precache - SequencePrecache( pmodel, STRING( m_iszIdle ) ); - SequencePrecache( pmodel, STRING( m_iszPlay ) ); - } - } -} - - -BOOL CBaseMonster :: CineCleanup( ) -{ - CCineMonster *pOldCine = m_pCine; - - // am I linked to a cinematic? - if (m_pCine) - { - // okay, reset me to what it thought I was before - m_pCine->m_hTargetEnt = NULL; - pev->movetype = m_pCine->m_saved_movetype; - pev->solid = m_pCine->m_saved_solid; - pev->effects = m_pCine->m_saved_effects; - } - else - { - // arg, punt - pev->movetype = MOVETYPE_STEP;// this is evil - pev->solid = SOLID_SLIDEBOX; - } - m_pCine = NULL; - m_hTargetEnt = NULL; - m_pGoalEnt = NULL; - if (pev->deadflag == DEAD_DYING) - { - // last frame of death animation? - pev->health = 0; - pev->framerate = 0.0; - pev->solid = SOLID_NOT; - SetState( MONSTERSTATE_DEAD ); - pev->deadflag = DEAD_DEAD; - UTIL_SetSize( pev, pev->mins, Vector(pev->maxs.x, pev->maxs.y, pev->mins.z + 2) ); - - if ( pOldCine && FBitSet( pOldCine->pev->spawnflags, SF_SCRIPT_LEAVECORPSE ) ) - { - SetUse( NULL ); // BUGBUG -- This doesn't call Killed() - SetThink( NULL ); // This will probably break some stuff - SetTouch( NULL ); - } - else - SUB_StartFadeOut(); // SetThink( SUB_DoNothing ); - // This turns off animation & physics in case their origin ends up stuck in the world or something - StopAnimation(); - pev->movetype = MOVETYPE_NONE; - pev->effects |= EF_NOINTERP; // Don't interpolate either, assume the corpse is positioned in its final resting place - return FALSE; - } - - // If we actually played a sequence - if ( pOldCine && pOldCine->m_iszPlay ) - { - if ( !(pOldCine->pev->spawnflags & SF_SCRIPT_NOSCRIPTMOVEMENT) ) - { - // reset position - Vector new_origin, new_angle; - GetBonePosition( 0, new_origin, new_angle ); - - // Figure out how far they have moved - // We can't really solve this problem because we can't query the movement of the origin relative - // to the sequence. We can get the root bone's position as we do here, but there are - // cases where the root bone is in a different relative position to the entity's origin - // before/after the sequence plays. So we are stuck doing this: - - // !!!HACKHACK: Float the origin up and drop to floor because some sequences have - // irregular motion that can't be properly accounted for. - - // UNDONE: THIS SHOULD ONLY HAPPEN IF WE ACTUALLY PLAYED THE SEQUENCE. - Vector oldOrigin = pev->origin; - - // UNDONE: ugly hack. Don't move monster if they don't "seem" to move - // this really needs to be done with the AX,AY,etc. flags, but that aren't consistantly - // being set, so animations that really do move won't be caught. - if ((oldOrigin - new_origin).Length2D() < 8.0) - new_origin = oldOrigin; - - pev->origin.x = new_origin.x; - pev->origin.y = new_origin.y; - pev->origin.z += 1; - - pev->flags |= FL_ONGROUND; - int drop = DROP_TO_FLOOR( ENT(pev) ); - - // Origin in solid? Set to org at the end of the sequence - if ( drop < 0 ) - pev->origin = oldOrigin; - else if ( drop == 0 ) // Hanging in air? - { - pev->origin.z = new_origin.z; - pev->flags &= ~FL_ONGROUND; - } - // else entity hit floor, leave there - - // pEntity->pev->origin.z = new_origin.z + 5.0; // damn, got to fix this - - UTIL_SetOrigin( pev, pev->origin ); - pev->effects |= EF_NOINTERP; - } - - // We should have some animation to put these guys in, but for now it's idle. - // Due to NOINTERP above, there won't be any blending between this anim & the sequence - m_Activity = ACT_RESET; - } - // set them back into a normal state - pev->enemy = NULL; - if ( pev->health > 0 ) - m_IdealMonsterState = MONSTERSTATE_IDLE; // m_previousState; - else - { - // Dropping out because he got killed - // Can't call killed() no attacker and weirdness (late gibbing) may result - m_IdealMonsterState = MONSTERSTATE_DEAD; - SetConditions( bits_COND_LIGHT_DAMAGE ); - pev->deadflag = DEAD_DYING; - FCheckAITrigger(); - pev->deadflag = DEAD_NO; - } - - - // SetAnimation( m_MonsterState ); - ClearBits(pev->spawnflags, SF_MONSTER_WAIT_FOR_SCRIPT ); - - return TRUE; -} - - - - -class CScriptedSentence : public CBaseToggle -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FindThink( void ); - void EXPORT DelayThink( void ); - int ObjectCaps( void ) { return (CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - CBaseMonster *FindEntity( void ); - BOOL AcceptableSpeaker( CBaseMonster *pMonster ); - BOOL StartSentence( CBaseMonster *pTarget ); - - -private: - int m_iszSentence; // string index for idle animation - int m_iszEntity; // entity that is wanted for this sentence - float m_flRadius; // range to search - float m_flDuration; // How long the sentence lasts - float m_flRepeat; // repeat rate - float m_flAttenuation; - float m_flVolume; - BOOL m_active; - int m_iszListener; // name of entity to look at while talking -}; - -#define SF_SENTENCE_ONCE 0x0001 -#define SF_SENTENCE_FOLLOWERS 0x0002 // only say if following player -#define SF_SENTENCE_INTERRUPT 0x0004 // force talking except when dead -#define SF_SENTENCE_CONCURRENT 0x0008 // allow other people to keep talking - -TYPEDESCRIPTION CScriptedSentence::m_SaveData[] = -{ - DEFINE_FIELD( CScriptedSentence, m_iszSentence, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_iszEntity, FIELD_STRING ), - DEFINE_FIELD( CScriptedSentence, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flDuration, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flRepeat, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_flVolume, FIELD_FLOAT ), - DEFINE_FIELD( CScriptedSentence, m_active, FIELD_BOOLEAN ), - DEFINE_FIELD( CScriptedSentence, m_iszListener, FIELD_STRING ), -}; - - -IMPLEMENT_SAVERESTORE( CScriptedSentence, CBaseToggle ); - -LINK_ENTITY_TO_CLASS( scripted_sentence, CScriptedSentence ); - -void CScriptedSentence :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sentence")) - { - m_iszSentence = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "entity")) - { - m_iszEntity = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "duration")) - { - m_flDuration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "refire")) - { - m_flRepeat = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "attenuation")) - { - pev->impulse = atoi( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if(FStrEq(pkvd->szKeyName, "volume")) - { - m_flVolume = atof( pkvd->szValue ) * 0.1; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "listener")) - { - m_iszListener = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - - -void CScriptedSentence :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !m_active ) - return; -// ALERT( at_console, "Firing sentence: %s\n", STRING(m_iszSentence) ); - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time; -} - - -void CScriptedSentence :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - - m_active = TRUE; - // if no targetname, start now - if ( !pev->targetname ) - { - SetThink( &CScriptedSentence::FindThink ); - pev->nextthink = gpGlobals->time + 1.0; - } - - switch( pev->impulse ) - { - case 1: // Medium radius - m_flAttenuation = ATTN_STATIC; - break; - - case 2: // Large radius - m_flAttenuation = ATTN_NORM; - break; - - case 3: //EVERYWHERE - m_flAttenuation = ATTN_NONE; - break; - - default: - case 0: // Small radius - m_flAttenuation = ATTN_IDLE; - break; - } - pev->impulse = 0; - - // No volume, use normal - if ( m_flVolume <= 0 ) - m_flVolume = 1.0; -} - - -void CScriptedSentence :: FindThink( void ) -{ - CBaseMonster *pMonster = FindEntity(); - if ( pMonster ) - { - StartSentence( pMonster ); - if ( pev->spawnflags & SF_SENTENCE_ONCE ) - UTIL_Remove( this ); - SetThink( &CScriptedSentence::DelayThink ); - pev->nextthink = gpGlobals->time + m_flDuration + m_flRepeat; - m_active = FALSE; -// ALERT( at_console, "%s: found monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - } - else - { -// ALERT( at_console, "%s: can't find monster %s\n", STRING(m_iszSentence), STRING(m_iszEntity) ); - pev->nextthink = gpGlobals->time + m_flRepeat + 0.5; - } -} - - -void CScriptedSentence :: DelayThink( void ) -{ - m_active = TRUE; - if ( !pev->targetname ) - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CScriptedSentence::FindThink ); -} - - -BOOL CScriptedSentence :: AcceptableSpeaker( CBaseMonster *pMonster ) -{ - if ( pMonster ) - { - if ( pev->spawnflags & SF_SENTENCE_FOLLOWERS ) - { - if ( pMonster->m_hTargetEnt == 0 || !FClassnameIs(pMonster->m_hTargetEnt->pev, "player") ) - return FALSE; - } - BOOL override; - if ( pev->spawnflags & SF_SENTENCE_INTERRUPT ) - override = TRUE; - else - override = FALSE; - if ( pMonster->CanPlaySentence( override ) ) - return TRUE; - } - return FALSE; -} - - -CBaseMonster *CScriptedSentence :: FindEntity( void ) -{ - edict_t *pentTarget; - CBaseMonster *pMonster; - - - pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_iszEntity)); - pMonster = NULL; - - while (!FNullEnt(pentTarget)) - { - pMonster = GetMonsterPointer( pentTarget ); - if ( pMonster != NULL ) - { - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; -// ALERT( at_console, "%s (%s), not acceptable\n", STRING(pMonster->pev->classname), STRING(pMonster->pev->targetname) ); - } - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(m_iszEntity)); - } - - CBaseEntity *pEntity = NULL; - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, m_flRadius )) != NULL) - { - if (FClassnameIs( pEntity->pev, STRING(m_iszEntity))) - { - if ( FBitSet( pEntity->pev->flags, FL_MONSTER )) - { - pMonster = pEntity->MyMonsterPointer( ); - if ( AcceptableSpeaker( pMonster ) ) - return pMonster; - } - } - } - - return NULL; -} - - -BOOL CScriptedSentence :: StartSentence( CBaseMonster *pTarget ) -{ - if ( !pTarget ) - { - ALERT( at_aiconsole, "Not Playing sentence %s\n", STRING(m_iszSentence) ); - return FALSE; - } - - BOOL bConcurrent = FALSE; - if ( !(pev->spawnflags & SF_SENTENCE_CONCURRENT) ) - bConcurrent = TRUE; - - CBaseEntity *pListener = NULL; - if (!FStringNull(m_iszListener)) - { - float radius = m_flRadius; - - if ( FStrEq( STRING(m_iszListener ), "player" ) ) - radius = 4096; // Always find the player - - pListener = UTIL_FindEntityGeneric( STRING( m_iszListener ), pTarget->pev->origin, radius ); - } - - pTarget->PlayScriptedSentence( STRING(m_iszSentence), m_flDuration, m_flVolume, m_flAttenuation, bConcurrent, pListener ); - ALERT( at_aiconsole, "Playing sentence %s (%.1f)\n", STRING(m_iszSentence), m_flDuration ); - SUB_UseTargets( NULL, USE_TOGGLE, 0 ); - return TRUE; -} - - - - - -/* - -*/ - - -//========================================================= -// Furniture - this is the cool comment I cut-and-pasted -//========================================================= -class CFurniture : public CBaseMonster -{ -public: - void Spawn ( void ); - void Die( void ); - int Classify ( void ); - virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } -}; - - -LINK_ENTITY_TO_CLASS( monster_furniture, CFurniture ); - - -//========================================================= -// Furniture is killed -//========================================================= -void CFurniture :: Die ( void ) -{ - SetThink ( &CFurniture::SUB_Remove ); - pev->nextthink = gpGlobals->time; -} - -//========================================================= -// This used to have something to do with bees flying, but -// now it only initializes moving furniture in scripted sequences -//========================================================= -void CFurniture :: Spawn( ) -{ - PRECACHE_MODEL((char *)STRING(pev->model)); - SET_MODEL(ENT(pev), STRING(pev->model)); - - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - pev->health = 80000; - pev->takedamage = DAMAGE_AIM; - pev->effects = 0; - pev->yaw_speed = 0; - pev->sequence = 0; - pev->frame = 0; - -// pev->nextthink += 1.0; -// SetThink (WalkMonsterDelay); - - ResetSequenceInfo( ); - pev->frame = 0; - MonsterInit(); -} - -//========================================================= -// ID's Furniture as neutral (noone will attack it) -//========================================================= -int CFurniture::Classify ( void ) -{ - return CLASS_NONE; -} - - diff --git a/sdk/dlls/scripted.h b/sdk/dlls/scripted.h deleted file mode 100644 index 5a5c9b2..0000000 --- a/sdk/dlls/scripted.h +++ /dev/null @@ -1,107 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#ifndef SCRIPTED_H -#define SCRIPTED_H - -#ifndef SCRIPTEVENT_H -#include "scriptevent.h" -#endif - -#define SF_SCRIPT_WAITTILLSEEN 1 -#define SF_SCRIPT_EXITAGITATED 2 -#define SF_SCRIPT_REPEATABLE 4 -#define SF_SCRIPT_LEAVECORPSE 8 -//#define SF_SCRIPT_INTERPOLATE 16 // don't use, old bug -#define SF_SCRIPT_NOINTERRUPT 32 -#define SF_SCRIPT_OVERRIDESTATE 64 -#define SF_SCRIPT_NOSCRIPTMOVEMENT 128 - -#define SCRIPT_BREAK_CONDITIONS (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE) - -enum SS_INTERRUPT -{ - SS_INTERRUPT_IDLE = 0, - SS_INTERRUPT_BY_NAME, - SS_INTERRUPT_AI, -}; - -// when a monster finishes an AI scripted sequence, we can choose -// a schedule to place them in. These defines are the aliases to -// resolve worldcraft input to real schedules (sjb) -#define SCRIPT_FINISHSCHED_DEFAULT 0 -#define SCRIPT_FINISHSCHED_AMBUSH 1 - -class CCineMonster : public CBaseMonster -{ -public: - void Spawn( void ); - virtual void KeyValue( KeyValueData *pkvd ); - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual void Blocked( CBaseEntity *pOther ); - virtual void Touch( CBaseEntity *pOther ); - virtual int ObjectCaps( void ) { return (CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - virtual void Activate( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // void EXPORT CineSpawnThink( void ); - void EXPORT CineThink( void ); - void Pain( void ); - void Die( void ); - void DelayStart( int state ); - BOOL FindEntity( void ); - virtual void PossessEntity( void ); - - void ReleaseEntity( CBaseMonster *pEntity ); - void CancelScript( void ); - virtual BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); - virtual BOOL FCanOverrideState ( void ); - void SequenceDone ( CBaseMonster *pMonster ); - virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); - BOOL CanInterrupt( void ); - void AllowInterrupt( BOOL fAllow ); - int IgnoreConditions( void ); - - int m_iszIdle; // string index for idle animation - int m_iszPlay; // string index for scripted animation - int m_iszEntity; // entity that is wanted for this script - int m_fMoveTo; - int m_iFinishSchedule; - float m_flRadius; // range to search - float m_flRepeat; // repeat rate - - int m_iDelay; - float m_startTime; - - int m_saved_movetype; - int m_saved_solid; - int m_saved_effects; -// Vector m_vecOrigOrigin; - BOOL m_interruptable; -}; - -class CCineAI : public CCineMonster -{ - BOOL StartSequence( CBaseMonster *pTarget, int iszSeq, BOOL completeOnEmpty ); - void PossessEntity( void ); - BOOL FCanOverrideState ( void ); - virtual void FixScriptMonsterSchedule( CBaseMonster *pMonster ); -}; - - -#endif //SCRIPTED_H diff --git a/sdk/dlls/scriptevent.h b/sdk/dlls/scriptevent.h deleted file mode 100644 index 42377cf..0000000 --- a/sdk/dlls/scriptevent.h +++ /dev/null @@ -1,29 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef SCRIPTEVENT_H -#define SCRIPTEVENT_H - -#define SCRIPT_EVENT_DEAD 1000 // character is now dead -#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt -#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt -#define SCRIPT_EVENT_FIREEVENT 1003 // event now fires -#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) -#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence -#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) -#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes -#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) -#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time -#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) -#endif //SCRIPTEVENT_H diff --git a/sdk/dlls/shotgun.cpp b/sdk/dlls/shotgun.cpp deleted file mode 100644 index ff1e40c..0000000 --- a/sdk/dlls/shotgun.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "gamerules.h" - -// special deathmatch shotgun spreads -#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees -#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees - -enum shotgun_e { - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun ); - -void CShotgun::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_SHOTGUN; - SET_MODEL(ENT(pev), "models/w_shotgun.mdl"); - - m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE; - - FallInit();// get ready to fall -} - - -void CShotgun::Precache( void ) -{ - PRECACHE_MODEL("models/v_shotgun.mdl"); - PRECACHE_MODEL("models/w_shotgun.mdl"); - PRECACHE_MODEL("models/p_shotgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shotgunshell.mdl");// shotgun shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - - PRECACHE_SOUND ("weapons/dbarrel1.wav");//shotgun - PRECACHE_SOUND ("weapons/sbarrel1.wav");//shotgun - - PRECACHE_SOUND ("weapons/reload1.wav"); // shotgun reload - PRECACHE_SOUND ("weapons/reload3.wav"); // shotgun reload - -// PRECACHE_SOUND ("weapons/sshell1.wav"); // shotgun reload - played on client -// PRECACHE_SOUND ("weapons/sshell3.wav"); // shotgun reload - played on client - - PRECACHE_SOUND ("weapons/357_cock1.wav"); // gun empty sound - PRECACHE_SOUND ("weapons/scock1.wav"); // cock gun - - m_usSingleFire = PRECACHE_EVENT( 1, "events/shotgun1.sc" ); - m_usDoubleFire = PRECACHE_EVENT( 1, "events/shotgun2.sc" ); -} - -int CShotgun::AddToPlayer( CBasePlayer *pPlayer ) -{ - if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); - WRITE_BYTE( m_iId ); - MESSAGE_END(); - return TRUE; - } - return FALSE; -} - - -int CShotgun::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "buckshot"; - p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = SHOTGUN_MAX_CLIP; - p->iSlot = 2; - p->iPosition = 1; - p->iFlags = 0; - p->iId = m_iId = WEAPON_SHOTGUN; - p->iWeight = SHOTGUN_WEIGHT; - - return 1; -} - - - -BOOL CShotgun::Deploy( ) -{ - return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" ); -} - -void CShotgun::PrimaryAttack() -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = GetNextAttackDelay(0.15); - return; - } - - if (m_iClip <= 0) - { - Reload( ); - if (m_iClip == 0) - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip--; - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // regular old, untouched spread. - vecDir = m_pPlayer->FireBulletsPlayer( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSingleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.5; - - m_flNextPrimaryAttack = GetNextAttackDelay(0.75); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; - else - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; - m_fInSpecialReload = 0; -} - - -void CShotgun::SecondaryAttack( void ) -{ - // don't fire underwater - if (m_pPlayer->pev->waterlevel == 3) - { - PlayEmptySound( ); - m_flNextPrimaryAttack = GetNextAttackDelay(0.15); - return; - } - - if (m_iClip <= 1) - { - Reload( ); - PlayEmptySound( ); - return; - } - - m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - - m_iClip -= 2; - - - int flags; -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - Vector vecDir; - -#ifdef CLIENT_DLL - if ( bIsMultiplayer() ) -#else - if ( g_pGameRules->IsMultiplayer() ) -#endif - { - // tuned for deathmatch - vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - else - { - // untouched default single player - vecDir = m_pPlayer->FireBulletsPlayer( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usDoubleFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - if (m_iClip != 0) - m_flPumpTime = gpGlobals->time + 0.95; - - m_flNextPrimaryAttack = GetNextAttackDelay(1.5); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; - if (m_iClip != 0) - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; - else - m_flTimeWeaponIdle = 1.5; - - m_fInSpecialReload = 0; - -} - - -void CShotgun::Reload( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP) - return; - - // don't reload until recoil is done - if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) - return; - - // check to see if we're ready to reload - if (m_fInSpecialReload == 0) - { - SendWeaponAnim( SHOTGUN_START_RELOAD ); - m_fInSpecialReload = 1; - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = GetNextAttackDelay(1.0); - m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; - return; - } - else if (m_fInSpecialReload == 1) - { - if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) - return; - // was waiting for gun to move to side - m_fInSpecialReload = 2; - - if (RANDOM_LONG(0,1)) - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload1.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - else - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/reload3.wav", 1, ATTN_NORM, 0, 85 + RANDOM_LONG(0,0x1f)); - - SendWeaponAnim( SHOTGUN_RELOAD ); - - m_flNextReload = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; - } - else - { - // Add them to the clip - m_iClip += 1; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= 1; - m_fInSpecialReload = 1; - } -} - - -void CShotgun::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - - if ( m_flPumpTime && m_flPumpTime < gpGlobals->time ) - { - // play pumping sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_flPumpTime = 0; - } - - if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) - { - if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else if (m_fInSpecialReload != 0) - { - if (m_iClip != 8 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - Reload( ); - } - else - { - // reload debounce has timed out - SendWeaponAnim( SHOTGUN_PUMP ); - - // play cocking sound - EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); - m_fInSpecialReload = 0; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; - } - } - else - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.8) - { - iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); - } - else if (flRand <= 0.95) - { - iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - else - { - iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); - } - SendWeaponAnim( iAnim ); - } - } -} - - - -class CShotgunAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_shotbox.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_shotbox.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_BUCKSHOTBOX_GIVE, "buckshot", BUCKSHOT_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_buckshot, CShotgunAmmo ); - - diff --git a/sdk/dlls/singleplay_gamerules.cpp b/sdk/dlls/singleplay_gamerules.cpp deleted file mode 100644 index 398b8cc..0000000 --- a/sdk/dlls/singleplay_gamerules.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "skill.h" -#include "items.h" - -extern DLL_GLOBAL CGameRules *g_pGameRules; -extern DLL_GLOBAL BOOL g_fGameOver; -extern int gmsgDeathMsg; // client dll messages -extern int gmsgScoreInfo; -extern int gmsgMOTD; - -//========================================================= -//========================================================= -CHalfLifeRules::CHalfLifeRules( void ) -{ - RefreshSkillData(); -} - -//========================================================= -//========================================================= -void CHalfLifeRules::Think ( void ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsMultiplayer( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsDeathmatch ( void ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsCoOp( void ) -{ - return FALSE; -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ - if ( !pPlayer->m_pActiveItem ) - { - // player doesn't have an active item! - return TRUE; - } - - if ( !pPlayer->m_pActiveItem->CanHolster() ) - { - return FALSE; - } - - return TRUE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return FALSE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) -{ - return TRUE; -} - -void CHalfLifeRules :: InitHUD( CBasePlayer *pl ) -{ -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: ClientDisconnected( edict_t *pClient ) -{ -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlPlayerFallDamage( CBasePlayer *pPlayer ) -{ - // subtract off the speed at which a player is allowed to fall without being hurt, - // so damage will be based on speed beyond that, not the entire fall - pPlayer->m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; - return pPlayer->m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerSpawn( CBasePlayer *pPlayer ) -{ -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: AllowAutoTargetCrosshair( void ) -{ - return ( g_iSkillLevel == SKILL_EASY ); -} - -//========================================================= -//========================================================= -void CHalfLifeRules :: PlayerThink( CBasePlayer *pPlayer ) -{ -} - - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FPlayerCanRespawn( CBasePlayer *pPlayer ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -float CHalfLifeRules :: FlPlayerSpawnTime( CBasePlayer *pPlayer ) -{ - return gpGlobals->time;//now! -} - -//========================================================= -// IPointsForKill - how many points awarded to anyone -// that kills this player? -//========================================================= -int CHalfLifeRules :: IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - return 1; -} - -//========================================================= -// PlayerKilled - someone/something killed this player -//========================================================= -void CHalfLifeRules :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// Deathnotice -//========================================================= -void CHalfLifeRules::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ -} - -//========================================================= -// PlayerGotWeapon - player has grabbed a weapon that was -// sitting in the world -//========================================================= -void CHalfLifeRules :: PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) -{ -} - -//========================================================= -// FlWeaponRespawnTime - what is the time in the future -// at which this weapon may spawn? -//========================================================= -float CHalfLifeRules :: FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) -{ - return -1; -} - -//========================================================= -// FlWeaponRespawnTime - Returns 0 if the weapon can respawn -// now, otherwise it returns the time at which it can try -// to spawn again. -//========================================================= -float CHalfLifeRules :: FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) -{ - return 0; -} - -//========================================================= -// VecWeaponRespawnSpot - where should this weapon spawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules :: VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) -{ - return pWeapon->pev->origin; -} - -//========================================================= -// WeaponShouldRespawn - any conditions inhibiting the -// respawning of this weapon? -//========================================================= -int CHalfLifeRules :: WeaponShouldRespawn( CBasePlayerItem *pWeapon ) -{ - return GR_WEAPON_RESPAWN_NO; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::ItemShouldRespawn( CItem *pItem ) -{ - return GR_ITEM_RESPAWN_NO; -} - - -//========================================================= -// At what time in the future may this Item respawn? -//========================================================= -float CHalfLifeRules::FlItemRespawnTime( CItem *pItem ) -{ - return -1; -} - -//========================================================= -// Where should this item respawn? -// Some game variations may choose to randomize spawn locations -//========================================================= -Vector CHalfLifeRules::VecItemRespawnSpot( CItem *pItem ) -{ - return pItem->pev->origin; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules::IsAllowedToSpawn( CBaseEntity *pEntity ) -{ - return TRUE; -} - -//========================================================= -//========================================================= -void CHalfLifeRules::PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) -{ -} - -//========================================================= -//========================================================= -int CHalfLifeRules::AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) -{ - return GR_AMMO_RESPAWN_NO; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) -{ - return -1; -} - -//========================================================= -//========================================================= -Vector CHalfLifeRules::VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) -{ - return pAmmo->pev->origin; -} - -//========================================================= -//========================================================= -float CHalfLifeRules::FlHealthChargerRechargeTime( void ) -{ - return 0;// don't recharge -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerWeapons( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_GUN_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::DeadPlayerAmmo( CBasePlayer *pPlayer ) -{ - return GR_PLR_DROP_AMMO_NO; -} - -//========================================================= -//========================================================= -int CHalfLifeRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // why would a single player in half life need this? - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeRules :: FAllowMonsters( void ) -{ - return TRUE; -} diff --git a/sdk/dlls/skill.cpp b/sdk/dlls/skill.cpp deleted file mode 100644 index 4105983..0000000 --- a/sdk/dlls/skill.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// skill.cpp - code for skill level concerns -//========================================================= -#include "extdll.h" -#include "util.h" -#include "skill.h" - - -skilldata_t gSkillData; - - -//========================================================= -// take the name of a cvar, tack a digit for the skill level -// on, and return the value.of that Cvar -//========================================================= -float GetSkillCvar( const char *pName ) -{ - float flValue; - char szBuffer[ 64 ]; - - sprintf( szBuffer, "%s%d",pName, gSkillData.iSkillLevel ); - - flValue = CVAR_GET_FLOAT ( szBuffer ); - - if ( flValue <= 0 ) - { - ALERT ( at_console, "\n\n** GetSkillCVar Got a zero for %s **\n\n", szBuffer ); - } - - return flValue; -} - diff --git a/sdk/dlls/skill.h b/sdk/dlls/skill.h deleted file mode 100644 index 2246a01..0000000 --- a/sdk/dlls/skill.h +++ /dev/null @@ -1,147 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// skill.h - skill level concerns -//========================================================= - -struct skilldata_t -{ - - int iSkillLevel; // game skill level - -// Monster Health & Damage - float agruntHealth; - float agruntDmgPunch; - - float apacheHealth; - - float barneyHealth; - - float bigmommaHealthFactor; // Multiply each node's health by this - float bigmommaDmgSlash; // melee attack damage - float bigmommaDmgBlast; // mortar attack damage - float bigmommaRadiusBlast; // mortar attack radius - - float bullsquidHealth; - float bullsquidDmgBite; - float bullsquidDmgWhip; - float bullsquidDmgSpit; - - float gargantuaHealth; - float gargantuaDmgSlash; - float gargantuaDmgFire; - float gargantuaDmgStomp; - - float hassassinHealth; - - float headcrabHealth; - float headcrabDmgBite; - - float hgruntHealth; - float hgruntDmgKick; - float hgruntShotgunPellets; - float hgruntGrenadeSpeed; - - float houndeyeHealth; - float houndeyeDmgBlast; - - float slaveHealth; - float slaveDmgClaw; - float slaveDmgClawrake; - float slaveDmgZap; - - float ichthyosaurHealth; - float ichthyosaurDmgShake; - - float leechHealth; - float leechDmgBite; - - float controllerHealth; - float controllerDmgZap; - float controllerSpeedBall; - float controllerDmgBall; - - float nihilanthHealth; - float nihilanthZap; - - float scientistHealth; - - float snarkHealth; - float snarkDmgBite; - float snarkDmgPop; - - float zombieHealth; - float zombieDmgOneSlash; - float zombieDmgBothSlash; - - float turretHealth; - float miniturretHealth; - float sentryHealth; - - -// Player Weapons - float plrDmgCrowbar; - float plrDmg9MM; - float plrDmg357; - float plrDmgMP5; - float plrDmgM203Grenade; - float plrDmgBuckshot; - float plrDmgCrossbowClient; - float plrDmgCrossbowMonster; - float plrDmgRPG; - float plrDmgGauss; - float plrDmgEgonNarrow; - float plrDmgEgonWide; - float plrDmgHornet; - float plrDmgHandGrenade; - float plrDmgSatchel; - float plrDmgTripmine; - -// weapons shared by monsters - float monDmg9MM; - float monDmgMP5; - float monDmg12MM; - float monDmgHornet; - -// health/suit charge - float suitchargerCapacity; - float batteryCapacity; - float healthchargerCapacity; - float healthkitCapacity; - float scientistHeal; - -// monster damage adj - float monHead; - float monChest; - float monStomach; - float monLeg; - float monArm; - -// player damage adj - float plrHead; - float plrChest; - float plrStomach; - float plrLeg; - float plrArm; -}; - -extern DLL_GLOBAL skilldata_t gSkillData; -float GetSkillCvar( const char *pName ); - -extern DLL_GLOBAL int g_iSkillLevel; - -#define SKILL_EASY 1 -#define SKILL_MEDIUM 2 -#define SKILL_HARD 3 diff --git a/sdk/dlls/sound.cpp b/sdk/dlls/sound.cpp deleted file mode 100644 index c29bffa..0000000 --- a/sdk/dlls/sound.cpp +++ /dev/null @@ -1,1982 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// sound.cpp -//========================================================= - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "player.h" -#include "talkmonster.h" -#include "gamerules.h" - -#if !defined ( _WIN32 ) -#include -#endif - - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); - - -// ==================== GENERIC AMBIENT SOUND ====================================== - -// runtime pitch shift and volume fadein/out structure - -// NOTE: IF YOU CHANGE THIS STRUCT YOU MUST CHANGE THE SAVE/RESTORE VERSION NUMBER -// SEE BELOW (in the typedescription for the class) -typedef struct dynpitchvol -{ - // NOTE: do not change the order of these parameters - // NOTE: unless you also change order of rgdpvpreset array elements! - int preset; - - int pitchrun; // pitch shift % when sound is running 0 - 255 - int pitchstart; // pitch shift % when sound stops or starts 0 - 255 - int spinup; // spinup time 0 - 100 - int spindown; // spindown time 0 - 100 - - int volrun; // volume change % when sound is running 0 - 10 - int volstart; // volume change % when sound stops or starts 0 - 10 - int fadein; // volume fade in time 0 - 100 - int fadeout; // volume fade out time 0 - 100 - - // Low Frequency Oscillator - int lfotype; // 0) off 1) square 2) triangle 3) random - int lforate; // 0 - 1000, how fast lfo osciallates - - int lfomodpitch; // 0-100 mod of current pitch. 0 is off. - int lfomodvol; // 0-100 mod of current volume. 0 is off. - - int cspinup; // each trigger hit increments counter and spinup pitch - - - int cspincount; - - int pitch; - int spinupsav; - int spindownsav; - int pitchfrac; - - int vol; - int fadeinsav; - int fadeoutsav; - int volfrac; - - int lfofrac; - int lfomult; - - -} dynpitchvol_t; - -#define CDPVPRESETMAX 27 - -// presets for runtime pitch and vol modulation of ambient sounds - -dynpitchvol_t rgdpvpreset[CDPVPRESETMAX] = -{ -// pitch pstart spinup spindwn volrun volstrt fadein fadeout lfotype lforate modptch modvol cspnup -{1, 255, 75, 95, 95, 10, 1, 50, 95, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{2, 255, 85, 70, 88, 10, 1, 20, 88, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{3, 255, 100, 50, 75, 10, 1, 10, 75, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{4, 100, 100, 0, 0, 10, 1, 90, 90, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{5, 100, 100, 0, 0, 10, 1, 80, 80, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{6, 100, 100, 0, 0, 10, 1, 50, 70, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{7, 100, 100, 0, 0, 5, 1, 40, 50, 1, 50, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{8, 100, 100, 0, 0, 5, 1, 40, 50, 1, 150, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{9, 100, 100, 0, 0, 5, 1, 40, 50, 1, 750, 0, 10, 0, 0,0,0,0,0,0,0,0,0,0}, -{10,128, 100, 50, 75, 10, 1, 30, 40, 2, 8, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{11,128, 100, 50, 75, 10, 1, 30, 40, 2, 25, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{12,128, 100, 50, 75, 10, 1, 30, 40, 2, 70, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{13,50, 50, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{14,70, 70, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{15,90, 90, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{16,120, 120, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{17,180, 180, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{18,255, 255, 0, 0, 10, 1, 20, 50, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{19,200, 75, 90, 90, 10, 1, 50, 90, 2, 100, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{20,255, 75, 97, 90, 10, 1, 50, 90, 1, 40, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{21,100, 100, 0, 0, 10, 1, 30, 50, 3, 15, 20, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{22,160, 160, 0, 0, 10, 1, 50, 50, 3, 500, 25, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{23,255, 75, 88, 0, 10, 1, 40, 0, 0, 0, 0, 0, 5, 0,0,0,0,0,0,0,0,0,0}, -{24,200, 20, 95, 70, 10, 1, 70, 70, 3, 20, 50, 0, 0, 0,0,0,0,0,0,0,0,0,0}, -{25,180, 100, 50, 60, 10, 1, 40, 60, 2, 90, 100, 100, 0, 0,0,0,0,0,0,0,0,0,0}, -{26,60, 60, 0, 0, 10, 1, 40, 70, 3, 80, 20, 50, 0, 0,0,0,0,0,0,0,0,0,0}, -{27,128, 90, 10, 10, 10, 1, 20, 40, 1, 5, 10, 20, 0, 0,0,0,0,0,0,0,0,0,0} -}; - -class CAmbientGeneric : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT RampThink( void ); - void InitModulationParms(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - float m_flAttenuation; // attenuation value - dynpitchvol_t m_dpv; - - BOOL m_fActive; // only TRUE when the entity is playing a looping sound - BOOL m_fLooping; // TRUE when the sound played will loop -}; - -LINK_ENTITY_TO_CLASS( ambient_generic, CAmbientGeneric ); -TYPEDESCRIPTION CAmbientGeneric::m_SaveData[] = -{ - DEFINE_FIELD( CAmbientGeneric, m_flAttenuation, FIELD_FLOAT ), - DEFINE_FIELD( CAmbientGeneric, m_fActive, FIELD_BOOLEAN ), - DEFINE_FIELD( CAmbientGeneric, m_fLooping, FIELD_BOOLEAN ), - - // HACKHACK - This is not really in the spirit of the save/restore design, but save this - // out as a binary data block. If the dynpitchvol_t is changed, old saved games will NOT - // load these correctly, so bump the save/restore version if you change the size of the struct - // The right way to do this is to split the input parms (read in keyvalue) into members and re-init this - // struct in Precache(), but it's unlikely that the struct will change, so it's not worth the time right now. - DEFINE_ARRAY( CAmbientGeneric, m_dpv, FIELD_CHARACTER, sizeof(dynpitchvol_t) ), -}; - -IMPLEMENT_SAVERESTORE( CAmbientGeneric, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CAmbientGeneric :: Spawn( void ) -{ -/* - -1 : "Default" - 0 : "Everywhere" - 200 : "Small Radius" - 125 : "Medium Radius" - 80 : "Large Radius" -*/ - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_EVERYWHERE) ) - { - m_flAttenuation = ATTN_NONE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_SMALLRADIUS) ) - { - m_flAttenuation = ATTN_IDLE; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_MEDIUMRADIUS) ) - { - m_flAttenuation = ATTN_STATIC; - } - else if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_LARGERADIUS) ) - { - m_flAttenuation = ATTN_NORM; - } - else - {// if the designer didn't set a sound attenuation, default to one. - m_flAttenuation = ATTN_STATIC; - } - - char* szSoundFile = (char*) STRING(pev->message); - - if ( FStringNull( pev->message ) || strlen( szSoundFile ) < 1 ) - { - ALERT( at_error, "EMPTY AMBIENT AT: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CAmbientGeneric::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - // Set up think function for dynamic modification - // of ambient sound's pitch or volume. Don't - // start thinking yet. - - SetThink(&CAmbientGeneric::RampThink); - pev->nextthink = 0; - - // allow on/off switching via 'use' function. - - SetUse ( &CAmbientGeneric::ToggleUse ); - - m_fActive = FALSE; - - if ( FBitSet ( pev->spawnflags, AMBIENT_SOUND_NOT_LOOPING ) ) - m_fLooping = FALSE; - else - m_fLooping = TRUE; - Precache( ); -} - - -void CAmbientGeneric :: Precache( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - - if ( !FStringNull( pev->message ) && strlen( szSoundFile ) > 1 ) - { - if (*szSoundFile != '!') - PRECACHE_SOUND(szSoundFile); - } - // init all dynamic modulation parms - InitModulationParms(); - - if ( !FBitSet (pev->spawnflags, AMBIENT_SOUND_START_SILENT ) ) - { - // start the sound ASAP - if (m_fLooping) - m_fActive = TRUE; - } - if ( m_fActive ) - { - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, SND_SPAWNING, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// RampThink - Think at 5hz if we are dynamically modifying -// pitch or volume of the playing sound. This function will -// ramp pitch and/or volume up or down, modify pitch/volume -// with lfo if active. - -void CAmbientGeneric :: RampThink( void ) -{ - char* szSoundFile = (char*) STRING(pev->message); - int pitch = m_dpv.pitch; - int vol = m_dpv.vol; - int flags = 0; - int fChanged = 0; // FALSE if pitch and vol remain unchanged this round - int prev; - - if (!m_dpv.spinup && !m_dpv.spindown && !m_dpv.fadein && !m_dpv.fadeout && !m_dpv.lfotype) - return; // no ramps or lfo, stop thinking - - // ============== - // pitch envelope - // ============== - if (m_dpv.spinup || m_dpv.spindown) - { - prev = m_dpv.pitchfrac >> 8; - - if (m_dpv.spinup > 0) - m_dpv.pitchfrac += m_dpv.spinup; - else if (m_dpv.spindown > 0) - m_dpv.pitchfrac -= m_dpv.spindown; - - pitch = m_dpv.pitchfrac >> 8; - - if (pitch > m_dpv.pitchrun) - { - pitch = m_dpv.pitchrun; - m_dpv.spinup = 0; // done with ramp up - } - - if (pitch < m_dpv.pitchstart) - { - pitch = m_dpv.pitchstart; - m_dpv.spindown = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - m_dpv.pitch = pitch; - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - // ================== - // amplitude envelope - // ================== - if (m_dpv.fadein || m_dpv.fadeout) - { - prev = m_dpv.volfrac >> 8; - - if (m_dpv.fadein > 0) - m_dpv.volfrac += m_dpv.fadein; - else if (m_dpv.fadeout > 0) - m_dpv.volfrac -= m_dpv.fadeout; - - vol = m_dpv.volfrac >> 8; - - if (vol > m_dpv.volrun) - { - vol = m_dpv.volrun; - m_dpv.fadein = 0; // done with ramp up - } - - if (vol < m_dpv.volstart) - { - vol = m_dpv.volstart; - m_dpv.fadeout = 0; // done with ramp down - - // shut sound off - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // return without setting nextthink - return; - } - - if (vol > 100) vol = 100; - if (vol < 1) vol = 1; - - m_dpv.vol = vol; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - // =================== - // pitch/amplitude LFO - // =================== - if (m_dpv.lfotype) - { - int pos; - - if (m_dpv.lfofrac > 0x6fffffff) - m_dpv.lfofrac = 0; - - // update lfo, lfofrac/255 makes a triangle wave 0-255 - m_dpv.lfofrac += m_dpv.lforate; - pos = m_dpv.lfofrac >> 8; - - if (m_dpv.lfofrac < 0) - { - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - pos = 0; - } - else if (pos > 255) - { - pos = 255; - m_dpv.lfofrac = (255 << 8); - m_dpv.lforate = -abs(m_dpv.lforate); - } - - switch(m_dpv.lfotype) - { - case LFO_SQUARE: - if (pos < 128) - m_dpv.lfomult = 255; - else - m_dpv.lfomult = 0; - - break; - case LFO_RANDOM: - if (pos == 255) - m_dpv.lfomult = RANDOM_LONG(0, 255); - break; - case LFO_TRIANGLE: - default: - m_dpv.lfomult = pos; - break; - } - - if (m_dpv.lfomodpitch) - { - prev = pitch; - - // pitch 0-255 - pitch += ((m_dpv.lfomult - 128) * m_dpv.lfomodpitch) / 100; - - if (pitch > 255) pitch = 255; - if (pitch < 1) pitch = 1; - - - fChanged |= (prev != pitch); - flags |= SND_CHANGE_PITCH; - } - - if (m_dpv.lfomodvol) - { - // vol 0-100 - prev = vol; - - vol += ((m_dpv.lfomult - 128) * m_dpv.lfomodvol) / 100; - - if (vol > 100) vol = 100; - if (vol < 0) vol = 0; - - fChanged |= (prev != vol); - flags |= SND_CHANGE_VOL; - } - - } - - // Send update to playing sound only if we actually changed - // pitch or volume in this routine. - - if (flags && fChanged) - { - if (pitch == PITCH_NORM) - pitch = PITCH_NORM + 1; // don't send 'no pitch' ! - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (vol * 0.01), m_flAttenuation, flags, pitch); - } - - // update ramps at 5hz - pev->nextthink = gpGlobals->time + 0.2; - return; -} - -// Init all ramp params in preparation to -// play a new sound - -void CAmbientGeneric :: InitModulationParms(void) -{ - int pitchinc; - - m_dpv.volrun = static_cast(pev->health * 10); // 0 - 100 - if (m_dpv.volrun > 100) m_dpv.volrun = 100; - if (m_dpv.volrun < 0) m_dpv.volrun = 0; - - // get presets - if (m_dpv.preset != 0 && m_dpv.preset <= CDPVPRESETMAX) - { - // load preset values - m_dpv = rgdpvpreset[m_dpv.preset - 1]; - - // fixup preset values, just like - // fixups in KeyValue routine. - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - - m_dpv.volstart *= 10; - m_dpv.volrun *= 10; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - - m_dpv.lforate *= 256; - - m_dpv.fadeinsav = m_dpv.fadein; - m_dpv.fadeoutsav = m_dpv.fadeout; - m_dpv.spinupsav = m_dpv.spinup; - m_dpv.spindownsav = m_dpv.spindown; - } - - m_dpv.fadein = m_dpv.fadeinsav; - m_dpv.fadeout = 0; - - if (m_dpv.fadein) - m_dpv.vol = m_dpv.volstart; - else - m_dpv.vol = m_dpv.volrun; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - if (m_dpv.spinup) - m_dpv.pitch = m_dpv.pitchstart; - else - m_dpv.pitch = m_dpv.pitchrun; - - if (m_dpv.pitch == 0) - m_dpv.pitch = PITCH_NORM; - - m_dpv.pitchfrac = m_dpv.pitch << 8; - m_dpv.volfrac = m_dpv.vol << 8; - - m_dpv.lfofrac = 0; - m_dpv.lforate = abs(m_dpv.lforate); - - m_dpv.cspincount = 1; - - if (m_dpv.cspinup) - { - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - } - - if ((m_dpv.spinupsav || m_dpv.spindownsav || (m_dpv.lfotype && m_dpv.lfomodpitch)) - && (m_dpv.pitch == PITCH_NORM)) - m_dpv.pitch = PITCH_NORM + 1; // must never send 'no pitch' as first pitch - // if we intend to pitch shift later! -} - -// -// ToggleUse - turns an ambient sound on or off. If the -// ambient is a looping sound, mark sound as active (m_fActive) -// if it's playing, innactive if not. If the sound is not -// a looping sound, never mark it as active. -// -void CAmbientGeneric :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - char* szSoundFile = (char*) STRING(pev->message); - float fraction; - - if ( useType != USE_TOGGLE ) - { - if ( (m_fActive && useType == USE_ON) || (!m_fActive && useType == USE_OFF) ) - return; - } - // Directly change pitch if arg passed. Only works if sound is already playing. - - if (useType == USE_SET && m_fActive) // Momentary buttons will pass down a float in here - { - - fraction = value; - - if ( fraction > 1.0 ) - fraction = 1.0; - if (fraction < 0.0) - fraction = 0.01; - - m_dpv.pitch = static_cast(fraction * 255); - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_CHANGE_PITCH, m_dpv.pitch); - - return; - } - - // Toggle - - // m_fActive is TRUE only if a looping sound is playing. - - if ( m_fActive ) - {// turn sound off - - if (m_dpv.cspinup) - { - // Don't actually shut off. Each toggle causes - // incremental spinup to max pitch - - if (m_dpv.cspincount <= m_dpv.cspinup) - { - int pitchinc; - - // start a new spinup - m_dpv.cspincount++; - - pitchinc = (255 - m_dpv.pitchstart) / m_dpv.cspinup; - - m_dpv.spinup = m_dpv.spinupsav; - m_dpv.spindown = 0; - - m_dpv.pitchrun = m_dpv.pitchstart + pitchinc * m_dpv.cspincount; - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - - pev->nextthink = gpGlobals->time + 0.1; - } - - } - else - { - m_fActive = FALSE; - - // HACKHACK - this makes the code in Precache() work properly after a save/restore - pev->spawnflags |= AMBIENT_SOUND_START_SILENT; - - if (m_dpv.spindownsav || m_dpv.fadeoutsav) - { - // spin it down (or fade it) before shutoff if spindown is set - m_dpv.spindown = m_dpv.spindownsav; - m_dpv.spinup = 0; - - m_dpv.fadeout = m_dpv.fadeoutsav; - m_dpv.fadein = 0; - pev->nextthink = gpGlobals->time + 0.1; - } - else - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - } - } - else - {// turn sound on - - // only toggle if this is a looping sound. If not looping, each - // trigger will cause the sound to play. If the sound is still - // playing from a previous trigger press, it will be shut off - // and then restarted. - - if (m_fLooping) - m_fActive = TRUE; - else - // shut sound off now - may be interrupting a long non-looping sound - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - 0, 0, SND_STOP, 0); - - // init all ramp params for startup - - InitModulationParms(); - - UTIL_EmitAmbientSound(ENT(pev), pev->origin, szSoundFile, - (m_dpv.vol * 0.01), m_flAttenuation, 0, m_dpv.pitch); - - pev->nextthink = gpGlobals->time + 0.1; - - } -} -// KeyValue - load keyvalue pairs into member data of the -// ambient generic. NOTE: called BEFORE spawn! - -void CAmbientGeneric :: KeyValue( KeyValueData *pkvd ) -{ - // NOTE: changing any of the modifiers in this code - // NOTE: also requires changing InitModulationParms code. - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_dpv.preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - - // pitchrun - else if (FStrEq(pkvd->szKeyName, "pitch")) - { - m_dpv.pitchrun = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchrun > 255) m_dpv.pitchrun = 255; - if (m_dpv.pitchrun < 0) m_dpv.pitchrun = 0; - } - - // pitchstart - else if (FStrEq(pkvd->szKeyName, "pitchstart")) - { - m_dpv.pitchstart = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - if (m_dpv.pitchstart > 255) m_dpv.pitchstart = 255; - if (m_dpv.pitchstart < 0) m_dpv.pitchstart = 0; - } - - // spinup - else if (FStrEq(pkvd->szKeyName, "spinup")) - { - m_dpv.spinup = atoi(pkvd->szValue); - - if (m_dpv.spinup > 100) m_dpv.spinup = 100; - if (m_dpv.spinup < 0) m_dpv.spinup = 0; - - if (m_dpv.spinup > 0) - m_dpv.spinup = (101 - m_dpv.spinup) * 64; - m_dpv.spinupsav = m_dpv.spinup; - pkvd->fHandled = TRUE; - } - - // spindown - else if (FStrEq(pkvd->szKeyName, "spindown")) - { - m_dpv.spindown = atoi(pkvd->szValue); - - if (m_dpv.spindown > 100) m_dpv.spindown = 100; - if (m_dpv.spindown < 0) m_dpv.spindown = 0; - - if (m_dpv.spindown > 0) - m_dpv.spindown = (101 - m_dpv.spindown) * 64; - m_dpv.spindownsav = m_dpv.spindown; - pkvd->fHandled = TRUE; - } - - // volstart - else if (FStrEq(pkvd->szKeyName, "volstart")) - { - m_dpv.volstart = atoi(pkvd->szValue); - - if (m_dpv.volstart > 10) m_dpv.volstart = 10; - if (m_dpv.volstart < 0) m_dpv.volstart = 0; - - m_dpv.volstart *= 10; // 0 - 100 - - pkvd->fHandled = TRUE; - } - - // fadein - else if (FStrEq(pkvd->szKeyName, "fadein")) - { - m_dpv.fadein = atoi(pkvd->szValue); - - if (m_dpv.fadein > 100) m_dpv.fadein = 100; - if (m_dpv.fadein < 0) m_dpv.fadein = 0; - - if (m_dpv.fadein > 0) - m_dpv.fadein = (101 - m_dpv.fadein) * 64; - m_dpv.fadeinsav = m_dpv.fadein; - pkvd->fHandled = TRUE; - } - - // fadeout - else if (FStrEq(pkvd->szKeyName, "fadeout")) - { - m_dpv.fadeout = atoi(pkvd->szValue); - - if (m_dpv.fadeout > 100) m_dpv.fadeout = 100; - if (m_dpv.fadeout < 0) m_dpv.fadeout = 0; - - if (m_dpv.fadeout > 0) - m_dpv.fadeout = (101 - m_dpv.fadeout) * 64; - m_dpv.fadeoutsav = m_dpv.fadeout; - pkvd->fHandled = TRUE; - } - - // lfotype - else if (FStrEq(pkvd->szKeyName, "lfotype")) - { - m_dpv.lfotype = atoi(pkvd->szValue); - if (m_dpv.lfotype > 4) m_dpv.lfotype = LFO_TRIANGLE; - pkvd->fHandled = TRUE; - } - - // lforate - else if (FStrEq(pkvd->szKeyName, "lforate")) - { - m_dpv.lforate = atoi(pkvd->szValue); - - if (m_dpv.lforate > 1000) m_dpv.lforate = 1000; - if (m_dpv.lforate < 0) m_dpv.lforate = 0; - - m_dpv.lforate *= 256; - - pkvd->fHandled = TRUE; - } - // lfomodpitch - else if (FStrEq(pkvd->szKeyName, "lfomodpitch")) - { - m_dpv.lfomodpitch = atoi(pkvd->szValue); - if (m_dpv.lfomodpitch > 100) m_dpv.lfomodpitch = 100; - if (m_dpv.lfomodpitch < 0) m_dpv.lfomodpitch = 0; - - - pkvd->fHandled = TRUE; - } - - // lfomodvol - else if (FStrEq(pkvd->szKeyName, "lfomodvol")) - { - m_dpv.lfomodvol = atoi(pkvd->szValue); - if (m_dpv.lfomodvol > 100) m_dpv.lfomodvol = 100; - if (m_dpv.lfomodvol < 0) m_dpv.lfomodvol = 0; - - pkvd->fHandled = TRUE; - } - - // cspinup - else if (FStrEq(pkvd->szKeyName, "cspinup")) - { - m_dpv.cspinup = atoi(pkvd->szValue); - if (m_dpv.cspinup > 100) m_dpv.cspinup = 100; - if (m_dpv.cspinup < 0) m_dpv.cspinup = 0; - - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// =================== ROOM SOUND FX ========================================== - -class CEnvSound : public CPointEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - - void Think( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - float m_flRadius; - float m_flRoomtype; -}; - -LINK_ENTITY_TO_CLASS( env_sound, CEnvSound ); -TYPEDESCRIPTION CEnvSound::m_SaveData[] = -{ - DEFINE_FIELD( CEnvSound, m_flRadius, FIELD_FLOAT ), - DEFINE_FIELD( CEnvSound, m_flRoomtype, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CEnvSound, CBaseEntity ); - - -void CEnvSound :: KeyValue( KeyValueData *pkvd ) -{ - - if (FStrEq(pkvd->szKeyName, "radius")) - { - m_flRadius = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "roomtype")) - { - m_flRoomtype = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } -} - -// returns TRUE if the given sound entity (pev) is in range -// and can see the given player entity (pevTarget) - -BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange) -{ - CEnvSound *pSound = GetClassPtr( (CEnvSound *)pev ); - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - Vector vecRange; - float flRange; - TraceResult tr; - - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - // check if line of sight crosses water boundary, or is blocked - - if ((tr.fInOpen && tr.fInWater) || tr.flFraction != 1) - return FALSE; - - // calc range from sound entity to player - - vecRange = tr.vecEndPos - vecSpot1; - flRange = vecRange.Length(); - - if (pSound->m_flRadius < flRange) - return FALSE; - - if (pflRange) - *pflRange = flRange; - - return TRUE; -} - -// -// A client that is visible and in range of a sound entity will -// have its room_type set by that sound entity. If two or more -// sound entities are contending for a client, then the nearest -// sound entity to the client will set the client's room_type. -// A client's room_type will remain set to its prior value until -// a new in-range, visible sound entity resets a new room_type. -// - -// CONSIDER: if player in water state, autoset roomtype to 14,15 or 16. - -void CEnvSound :: Think( void ) -{ - // get pointer to client if visible; FIND_CLIENT_IN_PVS will - // cycle through visible clients on consecutive calls. - - edict_t *pentPlayer = FIND_CLIENT_IN_PVS(edict()); - CBasePlayer *pPlayer = NULL; - - if (FNullEnt(pentPlayer)) - goto env_sound_Think_slow; // no player in pvs of sound entity, slow it down - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - float flRange; - - // check to see if this is the sound entity that is - // currently affecting this player - - if(!FNullEnt(pPlayer->m_pentSndLast) && (pPlayer->m_pentSndLast == ENT(pev))) { - - // this is the entity currently affecting player, check - // for validity - - if (pPlayer->m_flSndRoomtype != 0 && pPlayer->m_flSndRange != 0) { - - // we're looking at a valid sound entity affecting - // player, make sure it's still valid, update range - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) { - pPlayer->m_flSndRange = flRange; - goto env_sound_Think_fast; - } else { - - // current sound entity affecting player is no longer valid, - // flag this state by clearing room_type and range. - // NOTE: we do not actually change the player's room_type - // NOTE: until we have a new valid room_type to change it to. - - pPlayer->m_flSndRange = 0; - pPlayer->m_flSndRoomtype = 0; - goto env_sound_Think_slow; - } - } else { - // entity is affecting player but is out of range, - // wait passively for another entity to usurp it... - goto env_sound_Think_slow; - } - } - - // if we got this far, we're looking at an entity that is contending - // for current player sound. the closest entity to player wins. - - if (FEnvSoundInRange(pev, VARS(pentPlayer), &flRange)) - { - if (flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0) - { - // new entity is closer to player, so it wins. - pPlayer->m_pentSndLast = ENT(pev); - pPlayer->m_flSndRoomtype = m_flRoomtype; - pPlayer->m_flSndRange = flRange; - - // send room_type command to player's server. - // this should be a rare event - once per change of room_type - // only! - - //CLIENT_COMMAND(pentPlayer, "room_type %f", m_flRoomtype); - - MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, NULL, pentPlayer ); // use the magic #1 for "one client" - WRITE_SHORT( (short)m_flRoomtype ); // sequence number - MESSAGE_END(); - - // crank up nextthink rate for new active sound entity - // by falling through to think_fast... - } - // player is not closer to the contending sound entity, - // just fall through to think_fast. this effectively - // cranks up the think_rate of entities near the player. - } - - // player is in pvs of sound entity, but either not visible or - // not in range. do nothing, fall through to think_fast... - -env_sound_Think_fast: - pev->nextthink = gpGlobals->time + 0.25; - return; - -env_sound_Think_slow: - pev->nextthink = gpGlobals->time + 0.75; - return; -} - -// -// env_sound - spawn a sound entity that will set player roomtype -// when player moves in range and sight. -// -// -void CEnvSound :: Spawn( ) -{ - // spread think times - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); -} - -// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ====================================== - -#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group - -// group of related sentences - -typedef struct sentenceg -{ - char szgroupname[CBSENTENCENAME_MAX]; - int count; - unsigned char rgblru[CSENTENCE_LRU_MAX]; - -} SENTENCEG; - -#define CSENTENCEG_MAX 200 // max number of sentence groups -// globals - -SENTENCEG rgsentenceg[CSENTENCEG_MAX]; -int fSentencesInit = FALSE; - -char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -int gcallsentences = 0; - -// randomize list of sentence name indices - -void USENTENCEG_InitLRU(unsigned char *plru, int count) -{ - int i, j, k; - unsigned char temp; - - if (!fSentencesInit) - return; - - if (count > CSENTENCE_LRU_MAX) - count = CSENTENCE_LRU_MAX; - - for (i = 0; i < count; i++) - plru[i] = (unsigned char) i; - - // randomize array - for (i = 0; i < (count * 4); i++) - { - j = RANDOM_LONG(0,count-1); - k = RANDOM_LONG(0,count-1); - temp = plru[j]; - plru[j] = plru[k]; - plru[k] = temp; - } -} - -// ignore lru. pick next sentence from sentence group. Go in order until we hit the last sentence, -// then repeat list if freset is true. If freset is false, then repeat last sentence. -// ipick is passed in as the requested sentence ordinal. -// ipick 'next' is returned. -// return of -1 indicates an error. - -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) -{ - char *szgroupname; - unsigned char count; - char sznum[8]; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - - if (count == 0) - return -1; - - if (ipick >= count) - ipick = count-1; - - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - - if (ipick >= count) - { - if (freset) - // reset at end of list - return 0; - else - return count; - } - - return ipick + 1; -} - - - -// pick a random sentence from rootname0 to rootnameX. -// picks from the rgsentenceg[isentenceg] least -// recently used, modifies lru array. returns the sentencename. -// note, lru must be seeded with 0-n randomized sentence numbers, with the -// rest of the lru filled with -1. The first integer in the lru is -// actually the size of the list. Returns ipick, the ordinal -// of the picked sentence within the group. - -int USENTENCEG_Pick(int isentenceg, char *szfound) -{ - char *szgroupname; - unsigned char *plru; - unsigned char i; - unsigned char count; - char sznum[8]; - unsigned char ipick; - int ffound = FALSE; - - if (!fSentencesInit) - return -1; - - if (isentenceg < 0) - return -1; - - szgroupname = rgsentenceg[isentenceg].szgroupname; - count = rgsentenceg[isentenceg].count; - plru = rgsentenceg[isentenceg].rgblru; - - while (!ffound) - { - for (i = 0; i < count; i++) - if (plru[i] != 0xFF) - { - ipick = plru[i]; - plru[i] = 0xFF; - ffound = TRUE; - break; - } - - if (!ffound) - USENTENCEG_InitLRU(plru, count); - else - { - strcpy(szfound, "!"); - strcat(szfound, szgroupname); - sprintf(sznum, "%d", ipick); - strcat(szfound, sznum); - return ipick; - } - } - return -1; -} - -// ===================== SENTENCE GROUPS, MAIN ROUTINES ======================== - -// Given sentence group rootname (name without number suffix), -// get sentence group index (isentenceg). Returns -1 if no such name. - -int SENTENCEG_GetIndex(const char *szgroupname) -{ - int i; - - if (!fSentencesInit || !szgroupname) - return -1; - - // search rgsentenceg for match on szgroupname - - i = 0; - while (rgsentenceg[i].count) - { - if (!strcmp(szgroupname, rgsentenceg[i].szgroupname)) - return i; - i++; - } - - return -1; -} - -// given sentence group index, play random sentence for given entity. -// returns ipick - which sentence was picked to -// play from the group. Ipick is only needed if you plan on stopping -// the sound before playback is done (see SENTENCEG_Stop). - -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick > 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipick; -} - -// same as above, but takes sentence group name instead of index - -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch) -{ - char name[64]; - int ipick; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - { - ALERT( at_console, "No such sentence group %s\n", szgroupname ); - return -1; - } - - ipick = USENTENCEG_Pick(isentenceg, name); - if (ipick >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - - return ipick; -} - -// play sentences in sequential order from sentence group. Reset after last sentence. - -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, - float volume, float attenuation, int flags, int pitch, int ipick, int freset) -{ - char name[64]; - int ipicknext; - int isentenceg; - - if (!fSentencesInit) - return -1; - - name[0] = 0; - - isentenceg = SENTENCEG_GetIndex(szgroupname); - if (isentenceg < 0) - return -1; - - ipicknext = USENTENCEG_PickSequential(isentenceg, name, ipick, freset); - if (ipicknext >= 0 && name[0]) - EMIT_SOUND_DYN(entity, CHAN_VOICE, name, volume, attenuation, flags, pitch); - return ipicknext; -} - - -// for this entity, for the given sentence within the sentence group, stop -// the sentence. - -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick) -{ - char buffer[64]; - char sznum[8]; - - if (!fSentencesInit) - return; - - if (isentenceg < 0 || ipick < 0) - return; - - strcpy(buffer, "!"); - strcat(buffer, rgsentenceg[isentenceg].szgroupname); - sprintf(sznum, "%d", ipick); - strcat(buffer, sznum); - - STOP_SOUND(entity, CHAN_VOICE, buffer); -} - -// open sentences.txt, scan for groups, build rgsentenceg -// Should be called from world spawn, only works on the -// first call and is ignored subsequently. - -void SENTENCEG_Init() -{ - char buffer[512]; - char szgroup[64]; - int i, j; - int isentencegs; - - if (fSentencesInit) - return; - - memset(gszallsentencenames, 0, CVOXFILESENTENCEMAX * CBSENTENCENAME_MAX); - gcallsentences = 0; - - memset(rgsentenceg, 0, CSENTENCEG_MAX * sizeof(SENTENCEG)); - memset(buffer, 0, 512); - memset(szgroup, 0, 64); - isentencegs = -1; - - - int filePos = 0, fileSize; - byte *pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/sentences.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while ( memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL ) - { - // skip whitespace - i = 0; - while(buffer[i] && buffer[i] == ' ') - i++; - - if (!buffer[i]) - continue; - - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get sentence name - j = i; - while (buffer[j] && buffer[j] != ' ') - j++; - - if (!buffer[j]) - continue; - - if (gcallsentences > CVOXFILESENTENCEMAX) - { - ALERT (at_error, "Too many sentences in sentences.txt!\n"); - break; - } - - // null-terminate name and save in sentences array - buffer[j] = 0; - const char *pString = buffer + i; - - if ( strlen( pString ) >= CBSENTENCENAME_MAX ) - ALERT( at_warning, "Sentence %s longer than %d letters\n", pString, CBSENTENCENAME_MAX-1 ); - - strcpy( gszallsentencenames[gcallsentences++], pString ); - - j--; - if (j <= i) - continue; - if (!isdigit(buffer[j])) - continue; - - // cut out suffix numbers - while (j > i && isdigit(buffer[j])) - j--; - - if (j <= i) - continue; - - buffer[j+1] = 0; - - // if new name doesn't match previous group name, - // make a new group. - - if (strcmp(szgroup, &(buffer[i]))) - { - // name doesn't match with prev name, - // copy name into group, init count to 1 - isentencegs++; - if (isentencegs >= CSENTENCEG_MAX) - { - ALERT (at_error, "Too many sentence groups in sentences.txt!\n"); - break; - } - - strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); - rgsentenceg[isentencegs].count = 1; - - strcpy(szgroup, &(buffer[i])); - - continue; - } - else - { - //name matches with previous, increment group count - if (isentencegs >= 0) - rgsentenceg[isentencegs].count++; - } - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fSentencesInit = TRUE; - - // init lru lists - - i = 0; - - while (rgsentenceg[i].count && i < CSENTENCEG_MAX) - { - USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); - i++; - } - -} - -// convert sentence (sample) name to !sentencenum, return !sentencenum - -int SENTENCEG_Lookup(const char *sample, char *sentencenum) -{ - char sznum[8]; - - int i; - // this is a sentence name; lookup sentence number - // and give to engine as string. - for (i = 0; i < gcallsentences; i++) - if (!stricmp(gszallsentencenames[i], sample+1)) - { - if (sentencenum) - { - strcpy(sentencenum, "!"); - sprintf(sznum, "%d", i); - strcat(sentencenum, sznum); - } - return i; - } - // sentence name not found! - return -1; -} - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch) -{ - if (sample && *sample == '!') - { - char name[32]; - if (SENTENCEG_Lookup(sample, name) >= 0) - EMIT_SOUND_DYN2(entity, channel, name, volume, attenuation, flags, pitch); - else - ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); - } - else - EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); -} - -// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - EMIT_SOUND_DYN(entity, CHAN_STATIC, sample, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in group id, over the HEV suit speaker - -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndI(entity, isentenceg, fvol, ATTN_NORM, 0, pitch); -} - -// play a sentence, randomly selected from the passed in groupname - -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname) -{ - float fvol; - int pitch = PITCH_NORM; - - fvol = CVAR_GET_FLOAT("suitvolume"); - if (RANDOM_LONG(0,1)) - pitch = RANDOM_LONG(0,6) + 98; - - if (fvol > 0.05) - SENTENCEG_PlayRndSz(entity, groupname, fvol, ATTN_NORM, 0, pitch); -} - -// ===================== MATERIAL TYPE DETECTION, MAIN ROUTINES ======================== -// -// Used to detect the texture the player is standing on, map the -// texture name to a material type. Play footstep sound based -// on material type. - -int fTextureTypeInit = FALSE; - -#define CTEXTURESMAX 512 // max number of textures loaded - -int gcTextures = 0; -char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; // texture names -char grgchTextureType[CTEXTURESMAX]; // parallel array of texture types - -// open materials.txt, get size, alloc space, -// save in array. Only works first time called, -// ignored on subsequent calls. - -static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ) -{ - // Bullet-proofing - if ( !pMemFile || !pBuffer ) - return NULL; - - if ( filePos >= fileSize ) - return NULL; - - int i = filePos; - int last = fileSize; - - // fgets always NULL terminates, so only read bufferSize-1 characters - if ( last - filePos > (bufferSize-1) ) - last = filePos + (bufferSize-1); - - int stop = 0; - - // Stop at the next newline (inclusive) or end of buffer - while ( i < last && !stop ) - { - if ( pMemFile[i] == '\n' ) - stop = 1; - i++; - } - - - // If we actually advanced the pointer, copy it over - if ( i != filePos ) - { - // We read in size bytes - int size = i - filePos; - // copy it out - memcpy( pBuffer, pMemFile + filePos, sizeof(byte)*size ); - - // If the buffer isn't full, terminate (this is always true) - if ( size < bufferSize ) - pBuffer[size] = 0; - - // Update file pointer - filePos = i; - return pBuffer; - } - - // No data read, bail - return NULL; -} - - -void TEXTURETYPE_Init() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - - if (fTextureTypeInit) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - pMemFile = g_engfuncs.pfnLoadFileForMe( "sound/materials.txt", &fileSize ); - if ( !pMemFile ) - return; - - // for each line in the file... - while (memfgets(pMemFile, fileSize, filePos, buffer, 511) != NULL && (gcTextures < CTEXTURESMAX)) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - g_engfuncs.pfnFreeFile( pMemFile ); - - fTextureTypeInit = TRUE; -} - -// given texture name, find texture type -// if not found, return type 'concrete' - -// NOTE: this routine should ONLY be called if the -// current texture under the player changes! - -char TEXTURETYPE_Find(char *name) -{ - // CONSIDER: pre-sort texture names and perform faster binary search here - - for (int i = 0; i < gcTextures; i++) - { - if (!strnicmp(name, &(grgszTextureName[i][0]), CBTEXTURENAMEMAX-1)) - return (grgchTextureType[i]); - } - - return CHAR_TEX_CONCRETE; -} - -// play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the -// original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. -// returns volume of strike instrument (crowbar) to play - -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType) -{ -// hit the world, try to play sound based on texture material type - - char chTextureType; - float fvol; - float fvolbar; - char szbuffer[64]; - const char *pTextureName; - float rgfl1[3]; - float rgfl2[3]; - const char *rgsz[4]; - int cnt; - float fattn = ATTN_NORM; - - if ( !g_pGameRules->PlayTextureSounds() ) - return 0.0; - - CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); - - chTextureType = 0; - - if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) - // hit body - chTextureType = CHAR_TEX_FLESH; - else - { - // hit world - - // find texture under strike, get material type - - // copy trace vector into array for trace_texture - - vecSrc.CopyToArray(rgfl1); - vecEnd.CopyToArray(rgfl2); - - // get texture from entity or world (world is ent(0)) - if (pEntity) - pTextureName = TRACE_TEXTURE( ENT(pEntity->pev), rgfl1, rgfl2 ); - else - pTextureName = TRACE_TEXTURE( ENT(0), rgfl1, rgfl2 ); - - if ( pTextureName ) - { - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - strcpy(szbuffer, pTextureName); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; - - // ALERT ( at_console, "texture hit: %s\n", szbuffer); - - // get texture type - chTextureType = TEXTURETYPE_Find(szbuffer); - } - } - - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; - rgsz[0] = "player/pl_step1.wav"; - rgsz[1] = "player/pl_step2.wav"; - cnt = 2; - break; - case CHAR_TEX_METAL: fvol = 0.9; fvolbar = 0.3; - rgsz[0] = "player/pl_metal1.wav"; - rgsz[1] = "player/pl_metal2.wav"; - cnt = 2; - break; - case CHAR_TEX_DIRT: fvol = 0.9; fvolbar = 0.1; - rgsz[0] = "player/pl_dirt1.wav"; - rgsz[1] = "player/pl_dirt2.wav"; - rgsz[2] = "player/pl_dirt3.wav"; - cnt = 3; - break; - case CHAR_TEX_VENT: fvol = 0.5; fvolbar = 0.3; - rgsz[0] = "player/pl_duct1.wav"; - rgsz[1] = "player/pl_duct1.wav"; - cnt = 2; - break; - case CHAR_TEX_GRATE: fvol = 0.9; fvolbar = 0.5; - rgsz[0] = "player/pl_grate1.wav"; - rgsz[1] = "player/pl_grate4.wav"; - cnt = 2; - break; - case CHAR_TEX_TILE: fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "player/pl_tile1.wav"; - rgsz[1] = "player/pl_tile3.wav"; - rgsz[2] = "player/pl_tile2.wav"; - rgsz[3] = "player/pl_tile4.wav"; - cnt = 4; - break; - case CHAR_TEX_SLOSH: fvol = 0.9; fvolbar = 0.0; - rgsz[0] = "player/pl_slosh1.wav"; - rgsz[1] = "player/pl_slosh3.wav"; - rgsz[2] = "player/pl_slosh2.wav"; - rgsz[3] = "player/pl_slosh4.wav"; - cnt = 4; - break; - case CHAR_TEX_WOOD: fvol = 0.9; fvolbar = 0.2; - rgsz[0] = "debris/wood1.wav"; - rgsz[1] = "debris/wood2.wav"; - rgsz[2] = "debris/wood3.wav"; - cnt = 3; - break; - case CHAR_TEX_GLASS: - case CHAR_TEX_COMPUTER: - fvol = 0.8; fvolbar = 0.2; - rgsz[0] = "debris/glass1.wav"; - rgsz[1] = "debris/glass2.wav"; - rgsz[2] = "debris/glass3.wav"; - cnt = 3; - break; - case CHAR_TEX_FLESH: - if (iBulletType == BULLET_PLAYER_CROWBAR) - return 0.0; // crowbar already makes this sound - fvol = 1.0; fvolbar = 0.2; - rgsz[0] = "weapons/bullet_hit1.wav"; - rgsz[1] = "weapons/bullet_hit2.wav"; - fattn = 1.0; - cnt = 2; - break; - } - - // did we hit a breakable? - - if (pEntity && FClassnameIs(pEntity->pev, "func_breakable")) - { - // drop volumes, the object will already play a damaged sound - fvol /= 1.5; - fvolbar /= 2.0; - } - else if (chTextureType == CHAR_TEX_COMPUTER) - { - // play random spark if computer - - if ( ptr->flFraction != 1.0 && RANDOM_LONG(0,1)) - { - UTIL_Sparks( ptr->vecEndPos ); - - float flVolume = RANDOM_FLOAT ( 0.7 , 1.0 );//random volume range - switch ( RANDOM_LONG(0,1) ) - { - case 0: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark5.wav", flVolume, ATTN_NORM, 0, 100); break; - case 1: UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, "buttons/spark6.wav", flVolume, ATTN_NORM, 0, 100); break; - // case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark5.wav", flVolume, ATTN_NORM); break; - // case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "buttons/spark6.wav", flVolume, ATTN_NORM); break; - } - } - } - - // play material hit sound - UTIL_EmitAmbientSound(ENT(0), ptr->vecEndPos, rgsz[RANDOM_LONG(0,cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG(0,0xf)); - //EMIT_SOUND_DYN( ENT(m_pPlayer->pev), CHAN_WEAPON, rgsz[RANDOM_LONG(0,cnt-1)], fvol, ATTN_NORM, 0, 96 + RANDOM_LONG(0,0xf)); - - return fvolbar; -} - -// =================================================================================== -// -// Speaker class. Used for announcements per level, for door lock/unlock spoken voice. -// - -class CSpeaker : public CBaseEntity -{ -public: - void KeyValue( KeyValueData* pkvd); - void Spawn( void ); - void Precache( void ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT SpeakerThink( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } - - int m_preset; // preset number -}; - -LINK_ENTITY_TO_CLASS( speaker, CSpeaker ); -TYPEDESCRIPTION CSpeaker::m_SaveData[] = -{ - DEFINE_FIELD( CSpeaker, m_preset, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSpeaker, CBaseEntity ); - -// -// ambient_generic - general-purpose user-defined static sound -// -void CSpeaker :: Spawn( void ) -{ - const char *szSoundFile = STRING(pev->message); - - if ( !m_preset && (FStringNull( pev->message ) || strlen( szSoundFile ) < 1 )) - { - ALERT( at_error, "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", pev->origin.x, pev->origin.y, pev->origin.z ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CSpeaker::SUB_Remove ); - return; - } - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - - SetThink(&CSpeaker::SpeakerThink); - pev->nextthink = 0.0; - - // allow on/off switching via 'use' function. - - SetUse ( &CSpeaker::ToggleUse ); - - Precache( ); -} - -#define ANNOUNCE_MINUTES_MIN 0.25 -#define ANNOUNCE_MINUTES_MAX 2.25 - -void CSpeaker :: Precache( void ) -{ - if ( !FBitSet (pev->spawnflags, SPEAKER_START_SILENT ) ) - // set first announcement time for random n second - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(5.0, 15.0); -} -void CSpeaker :: SpeakerThink( void ) -{ - const char *szSoundFile = NULL; - float flvolume = pev->health * 0.1; - float flattenuation = 0.3; - int flags = 0; - int pitch = 100; - - - // Wait for the talkmonster to finish first. - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - { - pev->nextthink = CTalkMonster::g_talkWaitTime + RANDOM_FLOAT( 5, 10 ); - return; - } - - if (m_preset) - { - // go lookup preset text, assign szSoundFile - switch (m_preset) - { - case 1: szSoundFile = "C1A0_"; break; - case 2: szSoundFile = "C1A1_"; break; - case 3: szSoundFile = "C1A2_"; break; - case 4: szSoundFile = "C1A3_"; break; - case 5: szSoundFile = "C1A4_"; break; - case 6: szSoundFile = "C2A1_"; break; - case 7: szSoundFile = "C2A2_"; break; - case 8: szSoundFile = "C2A3_"; break; - case 9: szSoundFile = "C2A4_"; break; - case 10: szSoundFile = "C2A5_"; break; - case 11: szSoundFile = "C3A1_"; break; - case 12: szSoundFile = "C3A2_"; break; - } - } else - szSoundFile = (char*) STRING(pev->message); - - if (szSoundFile[0] == '!') - { - // play single sentence, one shot - UTIL_EmitAmbientSound ( ENT(pev), pev->origin, szSoundFile, - flvolume, flattenuation, flags, pitch); - - // shut off and reset - pev->nextthink = 0.0; - } - else - { - // make random announcement from sentence group - - if (SENTENCEG_PlayRndSz(ENT(pev), szSoundFile, flvolume, flattenuation, flags, pitch) < 0) - ALERT(at_console, "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile); - - // set next announcement time for random 5 to 10 minute delay - pev->nextthink = gpGlobals->time + - RANDOM_FLOAT(ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + 5; // time delay until it's ok to speak: used so that two NPCs don't talk at once - } - - return; -} - - -// -// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one. -// -void CSpeaker :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int fActive = (pev->nextthink > 0.0); - - // fActive is TRUE only if an announcement is pending - - if ( useType != USE_TOGGLE ) - { - // ignore if we're just turning something on that's already on, or - // turning something off that's already off. - if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) ) - return; - } - - if ( useType == USE_ON ) - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - return; - } - - if ( useType == USE_OFF ) - { - // turn off announcements - pev->nextthink = 0.0; - return; - - } - - // Toggle announcements - - - if ( fActive ) - { - // turn off announcements - pev->nextthink = 0.0; - } - else - { - // turn on announcements - pev->nextthink = gpGlobals->time + 0.1; - } -} - -// KeyValue - load keyvalue pairs into member data -// NOTE: called BEFORE spawn! - -void CSpeaker :: KeyValue( KeyValueData *pkvd ) -{ - - // preset - if (FStrEq(pkvd->szKeyName, "preset")) - { - m_preset = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} diff --git a/sdk/dlls/soundent.cpp b/sdk/dlls/soundent.cpp deleted file mode 100644 index ad5ef33..0000000 --- a/sdk/dlls/soundent.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "soundent.h" - - -LINK_ENTITY_TO_CLASS( soundent, CSoundEnt ); - -CSoundEnt *pSoundEnt; - -//========================================================= -// CSound - Clear - zeros all fields for a sound -//========================================================= -void CSound :: Clear ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_flExpireTime = 0; - m_iNext = SOUNDLIST_EMPTY; - m_iNextAudible = 0; -} - -//========================================================= -// Reset - clears the volume, origin, and type for a sound, -// but doesn't expire or unlink it. -//========================================================= -void CSound :: Reset ( void ) -{ - m_vecOrigin = g_vecZero; - m_iType = 0; - m_iVolume = 0; - m_iNext = SOUNDLIST_EMPTY; -} - -//========================================================= -// FIsSound - returns TRUE if the sound is an Audible sound -//========================================================= -BOOL CSound :: FIsSound ( void ) -{ - if ( m_iType & ( bits_SOUND_COMBAT | bits_SOUND_WORLD | bits_SOUND_PLAYER | bits_SOUND_DANGER ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// FIsScent - returns TRUE if the sound is actually a scent -//========================================================= -BOOL CSound :: FIsScent ( void ) -{ - if ( m_iType & ( bits_SOUND_CARCASS | bits_SOUND_MEAT | bits_SOUND_GARBAGE ) ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// Spawn -//========================================================= -void CSoundEnt :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - Initialize(); - - pev->nextthink = gpGlobals->time + 1; -} - -//========================================================= -// Think - at interval, the entire active sound list is checked -// for sounds that have ExpireTimes less than or equal -// to the current world time, and these sounds are deallocated. -//========================================================= -void CSoundEnt :: Think ( void ) -{ - int iSound; - int iPreviousSound; - - pev->nextthink = gpGlobals->time + 0.3;// how often to check the sound list. - - iPreviousSound = SOUNDLIST_EMPTY; - iSound = m_iActiveSound; - - while ( iSound != SOUNDLIST_EMPTY ) - { - if ( m_SoundPool[ iSound ].m_flExpireTime <= gpGlobals->time && m_SoundPool[ iSound ].m_flExpireTime != SOUND_NEVER_EXPIRE ) - { - int iNext = m_SoundPool[ iSound ].m_iNext; - - // move this sound back into the free list - FreeSound( iSound, iPreviousSound ); - - iSound = iNext; - } - else - { - iPreviousSound = iSound; - iSound = m_SoundPool[ iSound ].m_iNext; - } - } - - if ( m_fShowReport ) - { - ALERT ( at_aiconsole, "Soundlist: %d / %d (%d)\n", ISoundsInList( SOUNDLISTTYPE_ACTIVE ),ISoundsInList( SOUNDLISTTYPE_FREE ), ISoundsInList( SOUNDLISTTYPE_ACTIVE ) - m_cLastActiveSounds ); - m_cLastActiveSounds = ISoundsInList ( SOUNDLISTTYPE_ACTIVE ); - } - -} - -//========================================================= -// Precache - dummy function -//========================================================= -void CSoundEnt :: Precache ( void ) -{ -} - -//========================================================= -// FreeSound - clears the passed active sound and moves it -// to the top of the free list. TAKE CARE to only call this -// function for sounds in the Active list!! -//========================================================= -void CSoundEnt :: FreeSound ( int iSound, int iPrevious ) -{ - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - if ( iPrevious != SOUNDLIST_EMPTY ) - { - // iSound is not the head of the active list, so - // must fix the index for the Previous sound -// pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = m_SoundPool[ iSound ].m_iNext; - pSoundEnt->m_SoundPool[ iPrevious ].m_iNext = pSoundEnt->m_SoundPool[ iSound ].m_iNext; - } - else - { - // the sound we're freeing IS the head of the active list. - pSoundEnt->m_iActiveSound = pSoundEnt->m_SoundPool [ iSound ].m_iNext; - } - - // make iSound the head of the Free list. - pSoundEnt->m_SoundPool[ iSound ].m_iNext = pSoundEnt->m_iFreeSound; - pSoundEnt->m_iFreeSound = iSound; -} - -//========================================================= -// IAllocSound - moves a sound from the Free list to the -// Active list returns the index of the alloc'd sound -//========================================================= -int CSoundEnt :: IAllocSound( void ) -{ - int iNewSound; - - if ( m_iFreeSound == SOUNDLIST_EMPTY ) - { - // no free sound! - ALERT ( at_console, "Free Sound List is full!\n" ); - return SOUNDLIST_EMPTY; - } - - // there is at least one sound available, so move it to the - // Active sound list, and return its SoundPool index. - - iNewSound = m_iFreeSound;// copy the index of the next free sound - - m_iFreeSound = m_SoundPool[ m_iFreeSound ].m_iNext;// move the index down into the free list. - - m_SoundPool[ iNewSound ].m_iNext = m_iActiveSound;// point the new sound at the top of the active list. - - m_iActiveSound = iNewSound;// now make the new sound the top of the active list. You're done. - - return iNewSound; -} - -//========================================================= -// InsertSound - Allocates a free sound and fills it with -// sound info. -//========================================================= -void CSoundEnt :: InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) -{ - int iThisSound; - - if ( !pSoundEnt ) - { - // no sound ent! - return; - } - - iThisSound = pSoundEnt->IAllocSound(); - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Could not AllocSound() for InsertSound() (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iThisSound ].m_vecOrigin = vecOrigin; - pSoundEnt->m_SoundPool[ iThisSound ].m_iType = iType; - pSoundEnt->m_SoundPool[ iThisSound ].m_iVolume = iVolume; - pSoundEnt->m_SoundPool[ iThisSound ].m_flExpireTime = gpGlobals->time + flDuration; -} - -//========================================================= -// Initialize - clears all sounds and moves them into the -// free sound list. -//========================================================= -void CSoundEnt :: Initialize ( void ) -{ - int i; - int iSound; - - m_cLastActiveSounds = 0; - m_iFreeSound = 0; - m_iActiveSound = SOUNDLIST_EMPTY; - - for ( i = 0 ; i < MAX_WORLD_SOUNDS ; i++ ) - {// clear all sounds, and link them into the free sound list. - m_SoundPool[ i ].Clear(); - m_SoundPool[ i ].m_iNext = i + 1; - } - - m_SoundPool[ i - 1 ].m_iNext = SOUNDLIST_EMPTY;// terminate the list here. - - - // now reserve enough sounds for each client - for ( i = 0 ; i < gpGlobals->maxClients ; i++ ) - { - iSound = pSoundEnt->IAllocSound(); - - if ( iSound == SOUNDLIST_EMPTY ) - { - ALERT ( at_console, "Could not AllocSound() for Client Reserve! (DLL)\n" ); - return; - } - - pSoundEnt->m_SoundPool[ iSound ].m_flExpireTime = SOUND_NEVER_EXPIRE; - } - - if ( CVAR_GET_FLOAT("displaysoundlist") == 1 ) - { - m_fShowReport = TRUE; - } - else - { - m_fShowReport = FALSE; - } -} - -//========================================================= -// ISoundsInList - returns the number of sounds in the desired -// sound list. -//========================================================= -int CSoundEnt :: ISoundsInList ( int iListType ) -{ - int i; - int iThisSound = 0; - - if ( iListType == SOUNDLISTTYPE_FREE ) - { - iThisSound = m_iFreeSound; - } - else if ( iListType == SOUNDLISTTYPE_ACTIVE ) - { - iThisSound = m_iActiveSound; - } - else - { - ALERT ( at_console, "Unknown Sound List Type!\n" ); - } - - if ( iThisSound == SOUNDLIST_EMPTY ) - { - return 0; - } - - i = 0; - - while ( iThisSound != SOUNDLIST_EMPTY ) - { - i++; - - iThisSound = m_SoundPool[ iThisSound ].m_iNext; - } - - return i; -} - -//========================================================= -// ActiveList - returns the head of the active sound list -//========================================================= -int CSoundEnt :: ActiveList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iActiveSound; -} - -//========================================================= -// FreeList - returns the head of the free sound list -//========================================================= -int CSoundEnt :: FreeList ( void ) -{ - if ( !pSoundEnt ) - { - return SOUNDLIST_EMPTY; - } - - return pSoundEnt->m_iFreeSound; -} - -//========================================================= -// SoundPointerForIndex - returns a pointer to the instance -// of CSound at index's position in the sound pool. -//========================================================= -CSound* CSoundEnt :: SoundPointerForIndex( int iIndex ) -{ - if ( !pSoundEnt ) - { - return NULL; - } - - if ( iIndex > ( MAX_WORLD_SOUNDS - 1 ) ) - { - ALERT ( at_console, "SoundPointerForIndex() - Index too large!\n" ); - return NULL; - } - - if ( iIndex < 0 ) - { - ALERT ( at_console, "SoundPointerForIndex() - Index < 0!\n" ); - return NULL; - } - - return &pSoundEnt->m_SoundPool[ iIndex ]; -} - -//========================================================= -// Clients are numbered from 1 to MAXCLIENTS, but the client -// reserved sounds in the soundlist are from 0 to MAXCLIENTS - 1, -// so this function ensures that a client gets the proper index -// to his reserved sound in the soundlist. -//========================================================= -int CSoundEnt :: ClientSoundIndex ( edict_t *pClient ) -{ - int iReturn = ENTINDEX( pClient ) - 1; - -#ifdef _DEBUG - if ( iReturn < 0 || iReturn > gpGlobals->maxClients ) - { - ALERT ( at_console, "** ClientSoundIndex returning a bogus value! **\n" ); - } -#endif // _DEBUG - - return iReturn; -} diff --git a/sdk/dlls/soundent.h b/sdk/dlls/soundent.h deleted file mode 100644 index 150daac..0000000 --- a/sdk/dlls/soundent.h +++ /dev/null @@ -1,95 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -//========================================================= -// Soundent.h - the entity that spawns when the world -// spawns, and handles the world's active and free sound -// lists. -//========================================================= - -#define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. - -#define bits_SOUND_NONE 0 -#define bits_SOUND_COMBAT ( 1 << 0 )// gunshots, explosions -#define bits_SOUND_WORLD ( 1 << 1 )// door opening/closing, glass breaking -#define bits_SOUND_PLAYER ( 1 << 2 )// all noises generated by player. walking, shooting, falling, splashing -#define bits_SOUND_CARCASS ( 1 << 3 )// dead body -#define bits_SOUND_MEAT ( 1 << 4 )// gib or pork chop -#define bits_SOUND_DANGER ( 1 << 5 )// pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate -#define bits_SOUND_GARBAGE ( 1 << 6 )// trash cans, banana peels, old fast food bags. - -#define bits_ALL_SOUNDS 0xFFFFFFFF - -#define SOUNDLIST_EMPTY -1 - -#define SOUNDLISTTYPE_FREE 1// identifiers passed to functions that can operate on either list, to indicate which list to operate on. -#define SOUNDLISTTYPE_ACTIVE 2 - -#define SOUND_NEVER_EXPIRE -1 // with this set as a sound's ExpireTime, the sound will never expire. - -//========================================================= -// CSound - an instance of a sound in the world. -//========================================================= -class CSound -{ -public: - - void Clear ( void ); - void Reset ( void ); - - Vector m_vecOrigin; // sound's location in space - int m_iType; // what type of sound this is - int m_iVolume; // how loud the sound is - float m_flExpireTime; // when the sound should be purged from the list - int m_iNext; // index of next sound in this list ( Active or Free ) - int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds - - BOOL FIsSound( void ); - BOOL FIsScent( void ); -}; - -//========================================================= -// CSoundEnt - a single instance of this entity spawns when -// the world spawns. The SoundEnt's job is to update the -// world's Free and Active sound lists. -//========================================================= -class CSoundEnt : public CBaseEntity -{ -public: - - void Precache ( void ); - void Spawn( void ); - void Think( void ); - void Initialize ( void ); - - static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ); - static void FreeSound ( int iSound, int iPrevious ); - static int ActiveList( void );// return the head of the active list - static int FreeList( void );// return the head of the free list - static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list - static int ClientSoundIndex ( edict_t *pClient ); - - BOOL IsEmpty( void ) { return m_iActiveSound == SOUNDLIST_EMPTY; } - int ISoundsInList ( int iListType ); - int IAllocSound ( void ); - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } - - int m_iFreeSound; // index of the first sound in the free sound list - int m_iActiveSound; // indes of the first sound in the active sound list - int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) - BOOL m_fShowReport; // if true, dump information about free/active sounds. - -private: - CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; -}; diff --git a/sdk/dlls/spectator.cpp b/sdk/dlls/spectator.cpp deleted file mode 100644 index 5f91731..0000000 --- a/sdk/dlls/spectator.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// CBaseSpectator - -// YWB: UNDONE - -// Spectator functions -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "spectator.h" - -/* -=========== -SpectatorConnect - -called when a spectator connects to a server -============ -*/ -void CBaseSpectator::SpectatorConnect(void) -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} - -/* -=========== -SpectatorDisconnect - -called when a spectator disconnects from a server -============ -*/ -void CBaseSpectator::SpectatorDisconnect(void) -{ -} - -/* -================ -SpectatorImpulseCommand - -Called by SpectatorThink if the spectator entered an impulse -================ -*/ -void CBaseSpectator::SpectatorImpulseCommand(void) -{ - static edict_t *pGoal = NULL; - edict_t *pPreviousGoal; - edict_t *pCurrentGoal; - BOOL bFound; - - switch (pev->impulse) - { - case 1: - // teleport the spectator to the next spawn point - // note that if the spectator is tracking, this doesn't do - // much - pPreviousGoal = pGoal; - pCurrentGoal = pGoal; - // Start at the current goal, skip the world, and stop if we looped - // back around - - bFound = FALSE; - while (1) - { - pCurrentGoal = FIND_ENTITY_BY_CLASSNAME(pCurrentGoal, "info_player_deathmatch"); - // Looped around, failure - if (pCurrentGoal == pPreviousGoal) - { - ALERT(at_console, "Could not find a spawn spot.\n"); - break; - } - // Found a non-world entity, set success, otherwise, look for the next one. - if (!FNullEnt(pCurrentGoal)) - { - bFound = TRUE; - break; - } - } - - if (!bFound) // Didn't find a good spot. - break; - - pGoal = pCurrentGoal; - UTIL_SetOrigin( pev, pGoal->v.origin ); - pev->angles = pGoal->v.angles; - pev->fixangle = FALSE; - break; - default: - ALERT(at_console, "Unknown spectator impulse\n"); - break; - } - - pev->impulse = 0; -} - -/* -================ -SpectatorThink - -Called every frame after physics are run -================ -*/ -void CBaseSpectator::SpectatorThink(void) -{ - if (!(pev->flags & FL_SPECTATOR)) - { - pev->flags = FL_SPECTATOR; - } - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - if (pev->impulse) - SpectatorImpulseCommand(); -} - -/* -=========== -Spawn - - Called when spectator is initialized: - UNDONE: Is this actually being called because spectators are not allocated in normal fashion? -============ -*/ -void CBaseSpectator::Spawn() -{ - pev->flags = FL_SPECTATOR; - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NOCLIP; - - m_pGoalEnt = NULL; -} diff --git a/sdk/dlls/spectator.h b/sdk/dlls/spectator.h deleted file mode 100644 index 2f755d6..0000000 --- a/sdk/dlls/spectator.h +++ /dev/null @@ -1,27 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Spectator.h - -class CBaseSpectator : public CBaseEntity -{ -public: - void Spawn(); - void SpectatorConnect(void); - void SpectatorDisconnect(void); - void SpectatorThink(void); - -private: - void SpectatorImpulseCommand(void); -}; diff --git a/sdk/dlls/squad.h b/sdk/dlls/squad.h deleted file mode 100644 index ab34d1d..0000000 --- a/sdk/dlls/squad.h +++ /dev/null @@ -1,20 +0,0 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -//========================================================= -// squad.h -//========================================================= - -// these are special group roles that are assigned to members when the group is formed. -// the reason these are explicitly assigned and tasks like throwing grenades to flush out -// enemies is that it's bad to have two members trying to flank left at the same time, but -// ok to have two throwing grenades at the same time. When a squad member cannot attack the -// enemy, it will choose to execute its special role. -#define bits_SQUAD_FLANK_LEFT ( 1 << 0 ) -#define bits_SQUAD_FLANK_RIGHT ( 1 << 1 ) -#define bits_SQUAD_ADVANCE ( 1 << 2 ) -#define bits_SQUAD_FLUSH_ATTACK ( 1 << 3 ) diff --git a/sdk/dlls/squadmonster.cpp b/sdk/dlls/squadmonster.cpp deleted file mode 100644 index 2dbd9fc..0000000 --- a/sdk/dlls/squadmonster.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Squadmonster functions -//========================================================= -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "monsters.h" -#include "animation.h" -#include "saverestore.h" -#include "squadmonster.h" -#include "plane.h" - -//========================================================= -// Save/Restore -//========================================================= -TYPEDESCRIPTION CSquadMonster::m_SaveData[] = -{ - DEFINE_FIELD( CSquadMonster, m_hSquadLeader, FIELD_EHANDLE ), - DEFINE_ARRAY( CSquadMonster, m_hSquadMember, FIELD_EHANDLE, MAX_SQUAD_MEMBERS - 1 ), - - // DEFINE_FIELD( CSquadMonster, m_afSquadSlots, FIELD_INTEGER ), // these need to be reset after transitions! - DEFINE_FIELD( CSquadMonster, m_fEnemyEluded, FIELD_BOOLEAN ), - DEFINE_FIELD( CSquadMonster, m_flLastEnemySightTime, FIELD_TIME ), - - DEFINE_FIELD( CSquadMonster, m_iMySlot, FIELD_INTEGER ), - - -}; - -IMPLEMENT_SAVERESTORE( CSquadMonster, CBaseMonster ); - - -//========================================================= -// OccupySlot - if any slots of the passed slots are -// available, the monster will be assigned to one. -//========================================================= -BOOL CSquadMonster :: OccupySlot( int iDesiredSlots ) -{ - int i; - int iMask; - int iSquadSlots; - - if ( !InSquad() ) - { - return TRUE; - } - - if ( SquadEnemySplit() ) - { - // if the squad members aren't all fighting the same enemy, slots are disabled - // so that a squad member doesn't get stranded unable to engage his enemy because - // all of the attack slots are taken by squad members fighting other enemies. - m_iMySlot = bits_SLOT_SQUAD_SPLIT; - return TRUE; - } - - CSquadMonster *pSquadLeader = MySquadLeader(); - - if ( !( iDesiredSlots ^ pSquadLeader->m_afSquadSlots ) ) - { - // none of the desired slots are available. - return FALSE; - } - - iSquadSlots = pSquadLeader->m_afSquadSlots; - - for ( i = 0; i < NUM_SLOTS; i++ ) - { - iMask = 1<m_afSquadSlots |= iMask; - m_iMySlot = iMask; -// ALERT ( at_aiconsole, "Took slot %d - %d\n", i, m_hSquadLeader->m_afSquadSlots ); - return TRUE; - } - } - } - - return FALSE; -} - -//========================================================= -// VacateSlot -//========================================================= -void CSquadMonster :: VacateSlot() -{ - if ( m_iMySlot != bits_NO_SLOT && InSquad() ) - { -// ALERT ( at_aiconsole, "Vacated Slot %d - %d\n", m_iMySlot, m_hSquadLeader->m_afSquadSlots ); - MySquadLeader()->m_afSquadSlots &= ~m_iMySlot; - m_iMySlot = bits_NO_SLOT; - } -} - -//========================================================= -// ScheduleChange -//========================================================= -void CSquadMonster :: ScheduleChange ( void ) -{ - VacateSlot(); -} - -//========================================================= -// Killed -//========================================================= -void CSquadMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - VacateSlot(); - - if ( InSquad() ) - { - MySquadLeader()->SquadRemove( this ); - } - - CBaseMonster :: Killed ( pevAttacker, iGib ); -} - -// These functions are still awaiting conversion to CSquadMonster - - -//========================================================= -// -// SquadRemove(), remove pRemove from my squad. -// If I am pRemove, promote m_pSquadNext to leader -// -//========================================================= -void CSquadMonster :: SquadRemove( CSquadMonster *pRemove ) -{ - ASSERT( pRemove!=NULL ); - ASSERT( this->IsLeader() ); - ASSERT( pRemove->m_hSquadLeader == this ); - - // If I'm the leader, get rid of my squad - if (pRemove == MySquadLeader()) - { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) - { - CSquadMonster *pMember = MySquadMember(i); - if (pMember) - { - pMember->m_hSquadLeader = NULL; - m_hSquadMember[i] = NULL; - } - } - } - else - { - CSquadMonster *pSquadLeader = MySquadLeader(); - if (pSquadLeader) - { - for (int i = 0; i < MAX_SQUAD_MEMBERS-1;i++) - { - if (pSquadLeader->m_hSquadMember[i] == this) - { - pSquadLeader->m_hSquadMember[i] = NULL; - break; - } - } - } - } - - pRemove->m_hSquadLeader = NULL; -} - -//========================================================= -// -// SquadAdd(), add pAdd to my squad -// -//========================================================= -BOOL CSquadMonster :: SquadAdd( CSquadMonster *pAdd ) -{ - ASSERT( pAdd!=NULL ); - ASSERT( !pAdd->InSquad() ); - ASSERT( this->IsLeader() ); - - for (int i = 0; i < MAX_SQUAD_MEMBERS-1; i++) - { - if (m_hSquadMember[i] == 0) - { - m_hSquadMember[i] = pAdd; - pAdd->m_hSquadLeader = this; - return TRUE; - } - } - return FALSE; - // should complain here -} - - -//========================================================= -// -// SquadPasteEnemyInfo - called by squad members that have -// current info on the enemy so that it can be stored for -// members who don't have current info. -// -//========================================================= -void CSquadMonster :: SquadPasteEnemyInfo ( void ) -{ - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) - pSquadLeader->m_vecEnemyLKP = m_vecEnemyLKP; -} - -//========================================================= -// -// SquadCopyEnemyInfo - called by squad members who don't -// have current info on the enemy. Reads from the same fields -// in the leader's data that other squad members write to, -// so the most recent data is always available here. -// -//========================================================= -void CSquadMonster :: SquadCopyEnemyInfo ( void ) -{ - CSquadMonster *pSquadLeader = MySquadLeader( ); - if (pSquadLeader) - m_vecEnemyLKP = pSquadLeader->m_vecEnemyLKP; -} - -//========================================================= -// -// SquadMakeEnemy - makes everyone in the squad angry at -// the same entity. -// -//========================================================= -void CSquadMonster :: SquadMakeEnemy ( CBaseEntity *pEnemy ) -{ - if (!InSquad()) - return; - - if ( !pEnemy ) - { - ALERT ( at_console, "ERROR: SquadMakeEnemy() - pEnemy is NULL!\n" ); - return; - } - - CSquadMonster *pSquadLeader = MySquadLeader( ); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember) - { - // reset members who aren't activly engaged in fighting - if (pMember->m_hEnemy != pEnemy && !pMember->HasConditions( bits_COND_SEE_ENEMY)) - { - if ( pMember->m_hEnemy != 0) - { - // remember their current enemy - pMember->PushEnemy( pMember->m_hEnemy, pMember->m_vecEnemyLKP ); - } - // give them a new enemy - pMember->m_hEnemy = pEnemy; - pMember->m_vecEnemyLKP = pEnemy->pev->origin; - pMember->SetConditions ( bits_COND_NEW_ENEMY ); - } - } - } -} - - -//========================================================= -// -// SquadCount(), return the number of members of this squad -// callable from leaders & followers -// -//========================================================= -int CSquadMonster :: SquadCount( void ) -{ - if (!InSquad()) - return 0; - - CSquadMonster *pSquadLeader = MySquadLeader(); - int squadCount = 0; - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - if (pSquadLeader->MySquadMember(i) != NULL) - squadCount++; - } - - return squadCount; -} - - -//========================================================= -// -// SquadRecruit(), get some monsters of my classification and -// link them as a group. returns the group size -// -//========================================================= -int CSquadMonster :: SquadRecruit( int searchRadius, int maxMembers ) -{ - int squadCount; - int iMyClass = Classify();// cache this monster's class - - - // Don't recruit if I'm already in a group - if ( InSquad() ) - return 0; - - if ( maxMembers < 2 ) - return 0; - - // I am my own leader - m_hSquadLeader = this; - squadCount = 1; - - CBaseEntity *pEntity = NULL; - - if ( !FStringNull( pev->netname ) ) - { - // I have a netname, so unconditionally recruit everyone else with that name. - pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); - while ( pEntity ) - { - CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer(); - - if ( pRecruit ) - { - if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && pRecruit != this ) - { - // minimum protection here against user error.in worldcraft. - if (!SquadAdd( pRecruit )) - break; - squadCount++; - } - } - - pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ) ); - } - } - else - { - while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, searchRadius )) != NULL) - { - CSquadMonster *pRecruit = pEntity->MySquadMonsterPointer( ); - - if ( pRecruit && pRecruit != this && pRecruit->IsAlive() && !pRecruit->m_pCine ) - { - // Can we recruit this guy? - if ( !pRecruit->InSquad() && pRecruit->Classify() == iMyClass && - ( (iMyClass != CLASS_ALIEN_MONSTER) || FStrEq(STRING(pev->classname), STRING(pRecruit->pev->classname))) && - FStringNull( pRecruit->pev->netname ) ) - { - TraceResult tr; - UTIL_TraceLine( pev->origin + pev->view_ofs, pRecruit->pev->origin + pev->view_ofs, ignore_monsters, pRecruit->edict(), &tr );// try to hit recruit with a traceline. - if ( tr.flFraction == 1.0 ) - { - if (!SquadAdd( pRecruit )) - break; - - squadCount++; - } - } - } - } - } - - // no single member squads - if (squadCount == 1) - { - m_hSquadLeader = NULL; - } - - return squadCount; -} - -//========================================================= -// CheckEnemy -//========================================================= -int CSquadMonster :: CheckEnemy ( CBaseEntity *pEnemy ) -{ - int iUpdatedLKP; - - iUpdatedLKP = CBaseMonster :: CheckEnemy ( m_hEnemy ); - - // communicate with squad members about the enemy IF this individual has the same enemy as the squad leader. - if ( InSquad() && (CBaseEntity *)m_hEnemy == MySquadLeader()->m_hEnemy ) - { - if ( iUpdatedLKP ) - { - // have new enemy information, so paste to the squad. - SquadPasteEnemyInfo(); - } - else - { - // enemy unseen, copy from the squad knowledge. - SquadCopyEnemyInfo(); - } - } - - return iUpdatedLKP; -} - -//========================================================= -// StartMonster -//========================================================= -void CSquadMonster :: StartMonster( void ) -{ - CBaseMonster :: StartMonster(); - - if ( ( m_afCapability & bits_CAP_SQUAD ) && !InSquad() ) - { - if ( !FStringNull( pev->netname ) ) - { - // if I have a groupname, I can only recruit if I'm flagged as leader - if ( !( pev->spawnflags & SF_SQUADMONSTER_LEADER ) ) - { - return; - } - } - - // try to form squads now. - int iSquadSize = SquadRecruit( 1024, 4 ); - - if ( iSquadSize ) - { - ALERT ( at_aiconsole, "Squad of %d %s formed\n", iSquadSize, STRING( pev->classname ) ); - } - - if ( IsLeader() && FClassnameIs ( pev, "monster_human_grunt" ) ) - { - SetBodygroup( 1, 1 ); // UNDONE: truly ugly hack - pev->skin = 0; - } - - } -} - -//========================================================= -// NoFriendlyFire - checks for possibility of friendly fire -// -// Builds a large box in front of the grunt and checks to see -// if any squad members are in that box. -//========================================================= -BOOL CSquadMonster :: NoFriendlyFire( void ) -{ - if ( !InSquad() ) - { - return TRUE; - } - - CPlane backPlane; - CPlane leftPlane; - CPlane rightPlane; - - Vector vecLeftSide; - Vector vecRightSide; - Vector v_left; - - //!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!! - - if ( m_hEnemy != 0 ) - { - UTIL_MakeVectors ( UTIL_VecToAngles( m_hEnemy->Center() - pev->origin ) ); - } - else - { - // if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot. - return FALSE; - } - - //UTIL_MakeVectors ( pev->angles ); - - vecLeftSide = pev->origin - ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); - vecRightSide = pev->origin + ( gpGlobals->v_right * ( pev->size.x * 1.5 ) ); - v_left = gpGlobals->v_right * -1; - - leftPlane.InitializePlane ( gpGlobals->v_right, vecLeftSide ); - rightPlane.InitializePlane ( v_left, vecRightSide ); - backPlane.InitializePlane ( gpGlobals->v_forward, pev->origin ); - -/* - ALERT ( at_console, "LeftPlane: %f %f %f : %f\n", leftPlane.m_vecNormal.x, leftPlane.m_vecNormal.y, leftPlane.m_vecNormal.z, leftPlane.m_flDist ); - ALERT ( at_console, "RightPlane: %f %f %f : %f\n", rightPlane.m_vecNormal.x, rightPlane.m_vecNormal.y, rightPlane.m_vecNormal.z, rightPlane.m_flDist ); - ALERT ( at_console, "BackPlane: %f %f %f : %f\n", backPlane.m_vecNormal.x, backPlane.m_vecNormal.y, backPlane.m_vecNormal.z, backPlane.m_flDist ); -*/ - - CSquadMonster *pSquadLeader = MySquadLeader(); - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember && pMember != this) - { - - if ( backPlane.PointInFront ( pMember->pev->origin ) && - leftPlane.PointInFront ( pMember->pev->origin ) && - rightPlane.PointInFront ( pMember->pev->origin) ) - { - // this guy is in the check volume! Don't shoot! - return FALSE; - } - } - } - - return TRUE; -} - -//========================================================= -// GetIdealState - surveys the Conditions information available -// and finds the best new state for a monster. -//========================================================= -MONSTERSTATE CSquadMonster :: GetIdealState ( void ) -{ - IScheduleFlags(); - - // If no schedule conditions, the new ideal state is probably the reason we're in here. - switch ( m_MonsterState ) - { - case MONSTERSTATE_IDLE: - case MONSTERSTATE_ALERT: - if ( HasConditions ( bits_COND_NEW_ENEMY ) && InSquad() ) - { - SquadMakeEnemy ( m_hEnemy ); - } - break; - default: - break; - } - - return CBaseMonster :: GetIdealState(); -} - -//========================================================= -// FValidateCover - determines whether or not the chosen -// cover location is a good one to move to. (currently based -// on proximity to others in the squad) -//========================================================= -BOOL CSquadMonster :: FValidateCover ( const Vector &vecCoverLocation ) -{ - if ( !InSquad() ) - { - return TRUE; - } - - if (SquadMemberInRange( vecCoverLocation, 128 )) - { - // another squad member is too close to this piece of cover. - return FALSE; - } - - return TRUE; -} - -//========================================================= -// SquadEnemySplit- returns TRUE if not all squad members -// are fighting the same enemy. -//========================================================= -BOOL CSquadMonster :: SquadEnemySplit ( void ) -{ - if (!InSquad()) - return FALSE; - - CSquadMonster *pSquadLeader = MySquadLeader(); - CBaseEntity *pEnemy = pSquadLeader->m_hEnemy; - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pMember = pSquadLeader->MySquadMember(i); - if (pMember != NULL && pMember->m_hEnemy != 0 && pMember->m_hEnemy != pEnemy) - { - return TRUE; - } - } - return FALSE; -} - -//========================================================= -// FValidateCover - determines whether or not the chosen -// cover location is a good one to move to. (currently based -// on proximity to others in the squad) -//========================================================= -BOOL CSquadMonster :: SquadMemberInRange ( const Vector &vecLocation, float flDist ) -{ - if (!InSquad()) - return FALSE; - - CSquadMonster *pSquadLeader = MySquadLeader(); - - for (int i = 0; i < MAX_SQUAD_MEMBERS; i++) - { - CSquadMonster *pSquadMember = pSquadLeader->MySquadMember(i); - if (pSquadMember && (vecLocation - pSquadMember->pev->origin ).Length2D() <= flDist) - return TRUE; - } - return FALSE; -} - - -extern Schedule_t slChaseEnemyFailed[]; - -Schedule_t *CSquadMonster::GetScheduleOfType( int iType ) -{ - switch ( iType ) - { - - case SCHED_CHASE_ENEMY_FAILED: - { - return &slChaseEnemyFailed[ 0 ]; - } - - default: - return CBaseMonster::GetScheduleOfType( iType ); - } -} - diff --git a/sdk/dlls/squadmonster.h b/sdk/dlls/squadmonster.h deleted file mode 100644 index f944022..0000000 --- a/sdk/dlls/squadmonster.h +++ /dev/null @@ -1,120 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// CSquadMonster - all the extra data for monsters that -// form squads. -//========================================================= - -#define SF_SQUADMONSTER_LEADER 32 - - -#define bits_NO_SLOT 0 - -// HUMAN GRUNT SLOTS -#define bits_SLOT_HGRUNT_ENGAGE1 ( 1 << 0 ) -#define bits_SLOT_HGRUNT_ENGAGE2 ( 1 << 1 ) -#define bits_SLOTS_HGRUNT_ENGAGE ( bits_SLOT_HGRUNT_ENGAGE1 | bits_SLOT_HGRUNT_ENGAGE2 ) - -#define bits_SLOT_HGRUNT_GRENADE1 ( 1 << 2 ) -#define bits_SLOT_HGRUNT_GRENADE2 ( 1 << 3 ) -#define bits_SLOTS_HGRUNT_GRENADE ( bits_SLOT_HGRUNT_GRENADE1 | bits_SLOT_HGRUNT_GRENADE2 ) - -// ALIEN GRUNT SLOTS -#define bits_SLOT_AGRUNT_HORNET1 ( 1 << 4 ) -#define bits_SLOT_AGRUNT_HORNET2 ( 1 << 5 ) -#define bits_SLOT_AGRUNT_CHASE ( 1 << 6 ) -#define bits_SLOTS_AGRUNT_HORNET ( bits_SLOT_AGRUNT_HORNET1 | bits_SLOT_AGRUNT_HORNET2 ) - -// HOUNDEYE SLOTS -#define bits_SLOT_HOUND_ATTACK1 ( 1 << 7 ) -#define bits_SLOT_HOUND_ATTACK2 ( 1 << 8 ) -#define bits_SLOT_HOUND_ATTACK3 ( 1 << 9 ) -#define bits_SLOTS_HOUND_ATTACK ( bits_SLOT_HOUND_ATTACK1 | bits_SLOT_HOUND_ATTACK2 | bits_SLOT_HOUND_ATTACK3 ) - -// global slots -#define bits_SLOT_SQUAD_SPLIT ( 1 << 10 )// squad members don't all have the same enemy - -#define NUM_SLOTS 11// update this every time you add/remove a slot. - -#define MAX_SQUAD_MEMBERS 5 - -//========================================================= -// CSquadMonster - for any monster that forms squads. -//========================================================= -class CSquadMonster : public CBaseMonster -{ -public: - // squad leader info - EHANDLE m_hSquadLeader; // who is my leader - EHANDLE m_hSquadMember[MAX_SQUAD_MEMBERS-1]; // valid only for leader - int m_afSquadSlots; - float m_flLastEnemySightTime; // last time anyone in the squad saw the enemy - BOOL m_fEnemyEluded; - - // squad member info - int m_iMySlot;// this is the behaviour slot that the monster currently holds in the squad. - - int CheckEnemy ( CBaseEntity *pEnemy ); - void StartMonster ( void ); - void VacateSlot( void ); - void ScheduleChange( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - BOOL OccupySlot( int iDesiredSlot ); - BOOL NoFriendlyFire( void ); - - // squad functions still left in base class - CSquadMonster *MySquadLeader( ) - { - CSquadMonster *pSquadLeader = (CSquadMonster *)((CBaseEntity *)m_hSquadLeader); - if (pSquadLeader != NULL) - return pSquadLeader; - return this; - } - CSquadMonster *MySquadMember( int i ) - { - if (i >= MAX_SQUAD_MEMBERS-1) - return this; - else - return (CSquadMonster *)((CBaseEntity *)m_hSquadMember[i]); - } - int InSquad ( void ) { return m_hSquadLeader != 0; } - int IsLeader ( void ) { return m_hSquadLeader == this; } - int SquadJoin ( int searchRadius ); - int SquadRecruit ( int searchRadius, int maxMembers ); - int SquadCount( void ); - void SquadRemove( CSquadMonster *pRemove ); - void SquadUnlink( void ); - BOOL SquadAdd( CSquadMonster *pAdd ); - void SquadDisband( void ); - void SquadAddConditions ( int iConditions ); - void SquadMakeEnemy ( CBaseEntity *pEnemy ); - void SquadPasteEnemyInfo ( void ); - void SquadCopyEnemyInfo ( void ); - BOOL SquadEnemySplit ( void ); - BOOL SquadMemberInRange( const Vector &vecLocation, float flDist ); - - virtual CSquadMonster *MySquadMonsterPointer( void ) { return this; } - - static TYPEDESCRIPTION m_SaveData[]; - - int Save( CSave &save ); - int Restore( CRestore &restore ); - - BOOL FValidateCover ( const Vector &vecCoverLocation ); - - MONSTERSTATE GetIdealState ( void ); - Schedule_t *GetScheduleOfType ( int iType ); -}; - diff --git a/sdk/dlls/squeakgrenade.cpp b/sdk/dlls/squeakgrenade.cpp deleted file mode 100644 index 3cd38f8..0000000 --- a/sdk/dlls/squeakgrenade.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "soundent.h" -#include "gamerules.h" - -enum w_squeak_e { - WSQUEAK_IDLE1 = 0, - WSQUEAK_FIDGET, - WSQUEAK_JUMP, - WSQUEAK_RUN, -}; - -enum squeak_e { - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -#ifndef CLIENT_DLL - -class CSqueakGrenade : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - int Classify( void ); - void EXPORT SuperBounceTouch( CBaseEntity *pOther ); - void EXPORT HuntThink( void ); - int BloodColor( void ) { return BLOOD_COLOR_YELLOW; } - void Killed( entvars_t *pevAttacker, int iGib ); - void GibMonster( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - static float m_flNextBounceSoundTime; - - // CBaseEntity *m_pTarget; - float m_flDie; - Vector m_vecTarget; - float m_flNextHunt; - float m_flNextHit; - Vector m_posPrev; - EHANDLE m_hOwner; - int m_iMyClass; -}; - -float CSqueakGrenade::m_flNextBounceSoundTime = 0; - -LINK_ENTITY_TO_CLASS( monster_snark, CSqueakGrenade ); -TYPEDESCRIPTION CSqueakGrenade::m_SaveData[] = -{ - DEFINE_FIELD( CSqueakGrenade, m_flDie, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_vecTarget, FIELD_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHunt, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_flNextHit, FIELD_TIME ), - DEFINE_FIELD( CSqueakGrenade, m_posPrev, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CSqueakGrenade, m_hOwner, FIELD_EHANDLE ), -}; - -IMPLEMENT_SAVERESTORE( CSqueakGrenade, CGrenade ); - -#define SQUEEK_DETONATE_DELAY 15.0 - -int CSqueakGrenade :: Classify ( void ) -{ - if (m_iMyClass != 0) - return m_iMyClass; // protect against recursion - - if (m_hEnemy != 0) - { - m_iMyClass = CLASS_INSECT; // no one cares about it - switch( m_hEnemy->Classify( ) ) - { - case CLASS_PLAYER: - case CLASS_HUMAN_PASSIVE: - case CLASS_HUMAN_MILITARY: - m_iMyClass = 0; - return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it - } - m_iMyClass = 0; - } - - return CLASS_ALIEN_BIOWEAPON; -} - -void CSqueakGrenade :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_BOUNCE; - pev->solid = SOLID_BBOX; - - SET_MODEL(ENT(pev), "models/w_squeak.mdl"); - UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CSqueakGrenade::SuperBounceTouch ); - SetThink( &CSqueakGrenade::HuntThink ); - pev->nextthink = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time + 1E6; - - pev->flags |= FL_MONSTER; - pev->takedamage = DAMAGE_AIM; - pev->health = gSkillData.snarkHealth; - pev->gravity = 0.5; - pev->friction = 0.5; - - pev->dmg = gSkillData.snarkDmgPop; - - m_flDie = gpGlobals->time + SQUEEK_DETONATE_DELAY; - - m_flFieldOfView = 0; // 180 degrees - - if ( pev->owner ) - m_hOwner = Instance( pev->owner ); - - m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned. - - pev->sequence = WSQUEAK_RUN; - ResetSequenceInfo( ); -} - -void CSqueakGrenade::Precache( void ) -{ - PRECACHE_MODEL("models/w_squeak.mdl"); - PRECACHE_SOUND("squeek/sqk_blast1.wav"); - PRECACHE_SOUND("common/bodysplat.wav"); - PRECACHE_SOUND("squeek/sqk_die1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt1.wav"); - PRECACHE_SOUND("squeek/sqk_hunt2.wav"); - PRECACHE_SOUND("squeek/sqk_hunt3.wav"); - PRECACHE_SOUND("squeek/sqk_deploy1.wav"); -} - - -void CSqueakGrenade :: Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->model = iStringNull;// make invisible - SetThink( &CSqueakGrenade::SUB_Remove ); - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - - // since squeak grenades never leave a body behind, clear out their takedamage now. - // Squeaks do a bit of radius damage when they pop, and that radius damage will - // continue to call this function unless we acknowledge the Squeak's death now. (sjb) - pev->takedamage = DAMAGE_NO; - - // play squeek blast - EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/sqk_blast1.wav", 1, 0.5, 0, PITCH_NORM); - - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 ); - - UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 ); - - if (m_hOwner != 0) - RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - else - RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST ); - - // reset owner so death message happens - if (m_hOwner != 0) - pev->owner = m_hOwner->edict(); - - CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS ); -} - -void CSqueakGrenade :: GibMonster( void ) -{ - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200); -} - - - -void CSqueakGrenade::HuntThink( void ) -{ - // ALERT( at_console, "think\n" ); - - if (!IsInWorld()) - { - SetTouch( NULL ); - UTIL_Remove( this ); - return; - } - - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // explode when ready - if (gpGlobals->time >= m_flDie) - { - g_vecAttackDir = pev->velocity.Normalize( ); - pev->health = -1; - Killed( pev, 0 ); - return; - } - - // float - if (pev->waterlevel != 0) - { - if (pev->movetype == MOVETYPE_BOUNCE) - { - pev->movetype = MOVETYPE_FLY; - } - pev->velocity = pev->velocity * 0.9; - pev->velocity.z += 8.0; - } - else if (pev->movetype == MOVETYPE_FLY) - { - pev->movetype = MOVETYPE_BOUNCE; - } - - // return if not time to hunt - if (m_flNextHunt > gpGlobals->time) - return; - - m_flNextHunt = gpGlobals->time + 2.0; - - Vector vecDir; - TraceResult tr; - - Vector vecFlat = pev->velocity; - vecFlat.z = 0; - vecFlat = vecFlat.Normalize( ); - - UTIL_MakeVectors( pev->angles ); - - if (m_hEnemy == 0 || !m_hEnemy->IsAlive()) - { - // find target, bounce a bit towards it. - Look( 512 ); - m_hEnemy = BestVisibleEnemy( ); - } - - // squeek if it's about time blow up - if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3)) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F)); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - - // higher pitch as squeeker gets closer to detonation time - float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - if (flpitch < 80) - flpitch = 80; - - if (m_hEnemy != 0) - { - if (FVisible( m_hEnemy )) - { - vecDir = m_hEnemy->EyePosition() - pev->origin; - m_vecTarget = vecDir.Normalize( ); - } - - float flVel = pev->velocity.Length(); - float flAdj = 50.0 / (flVel + 10.0); - - if (flAdj > 1.2) - flAdj = 1.2; - - // ALERT( at_console, "think : enemy\n"); - - // ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z ); - - pev->velocity = pev->velocity * flAdj + m_vecTarget * 300; - } - - if (pev->flags & FL_ONGROUND) - { - pev->avelocity = Vector( 0, 0, 0 ); - } - else - { - if (pev->avelocity == Vector( 0, 0, 0)) - { - pev->avelocity.x = RANDOM_FLOAT( -100, 100 ); - pev->avelocity.z = RANDOM_FLOAT( -100, 100 ); - } - } - - if ((pev->origin - m_posPrev).Length() < 1.0) - { - pev->velocity.x = RANDOM_FLOAT( -100, 100 ); - pev->velocity.y = RANDOM_FLOAT( -100, 100 ); - } - m_posPrev = pev->origin; - - pev->angles = UTIL_VecToAngles( pev->velocity ); - pev->angles.z = 0; - pev->angles.x = 0; -} - - -void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther ) -{ - float flpitch; - - TraceResult tr = UTIL_GetGlobalTrace( ); - - // don't hit the guy that launched this grenade - if ( pev->owner && pOther->edict() == pev->owner ) - return; - - // at least until we've bounced once - pev->owner = NULL; - - pev->angles.x = 0; - pev->angles.z = 0; - - // avoid bouncing too much - if (m_flNextHit > gpGlobals->time) - return; - - // higher pitch as squeeker gets closer to detonation time - flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / SQUEEK_DETONATE_DELAY); - - if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time ) - { - // attack! - - // make sure it's me who has touched them - if (tr.pHit == pOther->edict()) - { - // and it's not another squeakgrenade - if (tr.pHit->v.modelindex != pev->modelindex) - { - // ALERT( at_console, "hit enemy\n"); - ClearMultiDamage( ); - pOther->TraceAttack(pev, gSkillData.snarkDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH ); - if (m_hOwner != 0) - ApplyMultiDamage( pev, m_hOwner->pev ); - else - ApplyMultiDamage( pev, pev ); - - pev->dmg += gSkillData.snarkDmgPop; // add more explosion damage - // m_flDie += 2.0; // add more life - - // make bite sound - EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch); - m_flNextAttack = gpGlobals->time + 0.5; - } - } - else - { - // ALERT( at_console, "been hit\n"); - } - } - - m_flNextHit = gpGlobals->time + 0.1; - m_flNextHunt = gpGlobals->time; - - if ( g_pGameRules->IsMultiplayer() ) - { - // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. - if ( gpGlobals->time < m_flNextBounceSoundTime ) - { - // too soon! - return; - } - } - - if (!(pev->flags & FL_ONGROUND)) - { - // play bounce sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch); - else if (flRndSound <= 0.66) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch); - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 ); - } - else - { - // skittering sound - CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 100, 0.1 ); - } - - m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second. -} - -#endif - -LINK_ENTITY_TO_CLASS( weapon_snark, CSqueak ); - - -void CSqueak::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_SNARK; - SET_MODEL(ENT(pev), "models/w_sqknest.mdl"); - - FallInit();//get ready to fall down. - - m_iDefaultAmmo = SNARK_DEFAULT_GIVE; - - pev->sequence = 1; - pev->animtime = gpGlobals->time; - pev->framerate = 1.0; -} - - -void CSqueak::Precache( void ) -{ - PRECACHE_MODEL("models/w_sqknest.mdl"); - PRECACHE_MODEL("models/v_squeak.mdl"); - PRECACHE_MODEL("models/p_squeak.mdl"); - PRECACHE_SOUND("squeek/sqk_hunt2.wav"); - PRECACHE_SOUND("squeek/sqk_hunt3.wav"); - UTIL_PrecacheOther("monster_snark"); - - m_usSnarkFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" ); -} - - -int CSqueak::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Snarks"; - p->iMaxAmmo1 = SNARK_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 3; - p->iId = m_iId = WEAPON_SNARK; - p->iWeight = SNARK_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - - - -BOOL CSqueak::Deploy( ) -{ - // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.5 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 100); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 100); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - return DefaultDeploy( "models/v_squeak.mdl", "models/p_squeak.mdl", SQUEAK_UP, "squeak" ); -} - - -void CSqueak::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - return; - } - - SendWeaponAnim( SQUEAK_DOWN ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); -} - - -void CSqueak::PrimaryAttack() -{ - if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) - { - UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - TraceResult tr; - Vector trace_origin; - - // HACK HACK: Ugly hacks to handle change in origin based on new physics code for players - // Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 ) - trace_origin = m_pPlayer->pev->origin; - if ( m_pPlayer->pev->flags & FL_DUCKING ) - { - trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN ); - } - - // find place to toss monster - UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); - - int flags; -#ifdef CLIENT_WEAPONS - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - if ( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) - { - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - -#ifndef CLIENT_DLL - CBaseEntity *pSqueak = CBaseEntity::Create( "monster_snark", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() ); - pSqueak->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity; -#endif - - // play hunt sound - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.5 ) - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, 105); - else - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, 105); - - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - m_fJustThrown = 1; - - m_flNextPrimaryAttack = GetNextAttackDelay(0.3); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - } - } -} - - -void CSqueak::SecondaryAttack( void ) -{ - -} - - -void CSqueak::WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if (m_fJustThrown) - { - m_fJustThrown = 0; - - if ( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) - { - RetireWeapon(); - return; - } - - SendWeaponAnim( SQUEAK_UP ); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - return; - } - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.75) - { - iAnim = SQUEAK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); - } - else if (flRand <= 0.875) - { - iAnim = SQUEAK_FIDGETFIT; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; - } - else - { - iAnim = SQUEAK_FIDGETNIP; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; - } - SendWeaponAnim( iAnim ); -} - -#endif diff --git a/sdk/dlls/stats.cpp b/sdk/dlls/stats.cpp deleted file mode 100644 index 0a7ea91..0000000 --- a/sdk/dlls/stats.cpp +++ /dev/null @@ -1,156 +0,0 @@ -//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ -// -// Purpose: New version of the slider bar -// -// $NoKeywords: $ -//============================================================================= - -#include "extdll.h" -#include "util.h" - -#include "cbase.h" -#include "player.h" -#include "trains.h" -#include "nodes.h" -#include "weapons.h" -#include "soundent.h" -#include "monsters.h" -#include "..\engine\shake.h" -#include "decals.h" -#include "gamerules.h" - - -float AmmoDamage( const char *pName ) -{ - if ( !pName ) - return 0; - - if ( !strcmp( pName, "9mm" ) ) - return gSkillData.plrDmg9MM; - if ( !strcmp( pName, "357" ) ) - return gSkillData.plrDmg357; - if ( !strcmp( pName, "ARgrenades" ) ) - return gSkillData.plrDmgM203Grenade; - if ( !strcmp( pName, "buckshot" ) ) - return gSkillData.plrDmgBuckshot; - if ( !strcmp( pName, "bolts") ) - return gSkillData.plrDmgCrossbowMonster; - if ( !strcmp( pName, "rockets") ) - return gSkillData.plrDmgRPG; - if ( !strcmp( pName, "uranium") ) - return gSkillData.plrDmgGauss; - if ( !strcmp( pName, "Hand Grenade") ) - return gSkillData.plrDmgHandGrenade; - if ( !strcmp( pName, "Satchel Charge") ) - return gSkillData.plrDmgSatchel; - if ( !strcmp( pName, "Trip Mine") ) - return gSkillData.plrDmgTripmine; - - return 0; -} - - -void UpdateStatsFile( float dataTime, char *pMapname, float health, float ammo, int skillLevel ) -{ - FILE *fp; - - fp = fopen( "stats.txt", "a" ); - if ( !fp ) - return; - fprintf( fp, "%6.2f, %6.2f, %6.2f, %s, %2d\n", dataTime, health, ammo, pMapname, skillLevel ); - fclose( fp ); -} - - -#define AMMO_THRESHOLD 10 // This much ammo goes by before it is "interesting" -#define HEALTH_THRESHOLD 10 // Same for health -#define OUTPUT_LATENCY 3 // This many seconds for ammo/health to settle - -typedef struct -{ - int lastAmmo; - float lastHealth; - float lastOutputTime; // NOTE: These times are in "game" time -- a running total of elapsed time since the game started - float nextOutputTime; - float dataTime; - float gameTime; - float lastGameTime; -} TESTSTATS; - -TESTSTATS gStats = {0,0,0,0,0,0,0}; - -void UpdateStats( CBasePlayer *pPlayer ) -{ - int i; - - int ammoCount[ MAX_AMMO_SLOTS ]; - memcpy( ammoCount, pPlayer->m_rgAmmo, MAX_AMMO_SLOTS * sizeof(int) ); - - // Keep a running time, so the graph doesn't overlap - - if ( gpGlobals->time < gStats.lastGameTime ) // Changed level or died, don't b0rk - { - gStats.lastGameTime = gpGlobals->time; - gStats.dataTime = gStats.gameTime; - } - - gStats.gameTime += gpGlobals->time - gStats.lastGameTime; - gStats.lastGameTime = gpGlobals->time; - - for (i = 0; i < MAX_ITEM_TYPES; i++) - { - CBasePlayerItem *p = pPlayer->m_rgpPlayerItems[i]; - while (p) - { - ItemInfo II; - - memset(&II, 0, sizeof(II)); - p->GetItemInfo(&II); - - int index = pPlayer->GetAmmoIndex(II.pszAmmo1); - if ( index >= 0 ) - ammoCount[ index ] += ((CBasePlayerWeapon *)p)->m_iClip; - - p = p->m_pNext; - } - } - - float ammo = 0; - for (i = 1; i < MAX_AMMO_SLOTS; i++) - { - ammo += ammoCount[i] * AmmoDamage( CBasePlayerItem::AmmoInfoArray[i].pszName ); - } - - float health = pPlayer->pev->health + pPlayer->pev->armorvalue * 2; // Armor is 2X health - float ammoDelta = fabs( ammo - gStats.lastAmmo ); - float healthDelta = fabs( health - gStats.lastHealth ); - int forceWrite = 0; - if ( health <= 0 && gStats.lastHealth > 0 ) - forceWrite = 1; - - if ( (ammoDelta > AMMO_THRESHOLD || healthDelta > HEALTH_THRESHOLD) && !forceWrite ) - { - if ( gStats.nextOutputTime == 0 ) - gStats.dataTime = gStats.gameTime; - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - - gStats.nextOutputTime = gStats.gameTime + OUTPUT_LATENCY; - } - else if ( (gStats.nextOutputTime != 0 && gStats.nextOutputTime < gStats.gameTime) || forceWrite ) - { - UpdateStatsFile( gStats.dataTime, (char *)STRING(gpGlobals->mapname), health, ammo, (int)CVAR_GET_FLOAT("skill") ); - - gStats.lastAmmo = ammo; - gStats.lastHealth = health; - gStats.lastOutputTime = gStats.gameTime; - gStats.nextOutputTime = 0; - } -} - -void InitStats( CBasePlayer *pPlayer ) -{ - gStats.lastGameTime = gpGlobals->time; // Fixup stats time -} - diff --git a/sdk/dlls/subs.cpp b/sdk/dlls/subs.cpp deleted file mode 100644 index 14814d8..0000000 --- a/sdk/dlls/subs.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== subs.cpp ======================================================== - - frequently used global functions - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include "nodes.h" -#include "doors.h" - -extern CGraph WorldGraph; - -extern BOOL FEntIsVisible(entvars_t* pev, entvars_t* pevTarget); - -extern DLL_GLOBAL int g_iSkillLevel; - - -// Landmark class -void CPointEntity :: Spawn( void ) -{ - pev->solid = SOLID_NOT; -// UTIL_SetSize(pev, g_vecZero, g_vecZero); -} - - -class CNullEntity : public CBaseEntity -{ -public: - void Spawn( void ); -}; - - -// Null Entity, remove on startup -void CNullEntity :: Spawn( void ) -{ - REMOVE_ENTITY(ENT(pev)); -} -LINK_ENTITY_TO_CLASS(info_null,CNullEntity); - -class CBaseDMStart : public CPointEntity -{ -public: - void KeyValue( KeyValueData *pkvd ); - BOOL IsTriggered( CBaseEntity *pEntity ); - -private: -}; - -// These are the new entry points to entities. -LINK_ENTITY_TO_CLASS(info_player_deathmatch,CBaseDMStart); -LINK_ENTITY_TO_CLASS(info_player_start,CPointEntity); -LINK_ENTITY_TO_CLASS(info_landmark,CPointEntity); - -void CBaseDMStart::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "master")) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -BOOL CBaseDMStart::IsTriggered( CBaseEntity *pEntity ) -{ - BOOL master = UTIL_IsMasterTriggered( pev->netname, pEntity ); - - return master; -} - -// This updates global tables that need to know about entities being removed -void CBaseEntity::UpdateOnRemove( void ) -{ - int i; - - if ( FBitSet( pev->flags, FL_GRAPHED ) ) - { - // this entity was a LinkEnt in the world node graph, so we must remove it from - // the graph since we are removing it from the world. - for ( i = 0 ; i < WorldGraph.m_cLinks ; i++ ) - { - if ( WorldGraph.m_pLinkPool [ i ].m_pLinkEnt == pev ) - { - // if this link has a link ent which is the same ent that is removing itself, remove it! - WorldGraph.m_pLinkPool [ i ].m_pLinkEnt = NULL; - } - } - } - if ( pev->globalname ) - gGlobalState.EntitySetState( pev->globalname, GLOBAL_DEAD ); -} - -// Convenient way to delay removing oneself -void CBaseEntity :: SUB_Remove( void ) -{ - UpdateOnRemove(); - if (pev->health > 0) - { - // this situation can screw up monsters who can't tell their entity pointers are invalid. - pev->health = 0; - ALERT( at_aiconsole, "SUB_Remove called on entity with health > 0\n"); - } - - REMOVE_ENTITY(ENT(pev)); -} - - -// Convenient way to explicitly do nothing (passed to functions that require a method) -void CBaseEntity :: SUB_DoNothing( void ) -{ -} - - -// Global Savedata for Delay -TYPEDESCRIPTION CBaseDelay::m_SaveData[] = -{ - DEFINE_FIELD( CBaseDelay, m_flDelay, FIELD_FLOAT ), - DEFINE_FIELD( CBaseDelay, m_iszKillTarget, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE( CBaseDelay, CBaseEntity ); - -void CBaseDelay :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "delay")) - { - m_flDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "killtarget")) - { - m_iszKillTarget = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - { - CBaseEntity::KeyValue( pkvd ); - } -} - - -/* -============================== -SUB_UseTargets - -If self.delay is set, a DelayedUse entity will be created that will actually -do the SUB_UseTargets after that many seconds have passed. - -Removes all entities with a targetname that match self.killtarget, -and removes them, so some events can remove other triggers. - -Search for (string)targetname in all entities that -match (string)self.target and call their .use function (if they have one) - -============================== -*/ -void CBaseEntity :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) -{ - // - // fire targets - // - if (!FStringNull(pev->target)) - { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); - } -} - - -void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - edict_t *pentTarget = NULL; - if ( !targetName ) - return; - - ALERT( at_aiconsole, "Firing: (%s)\n", targetName ); - - for (;;) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, targetName); - if (FNullEnt(pentTarget)) - break; - - CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget ); - if ( pTarget && !(pTarget->pev->flags & FL_KILLME) ) // Don't use dying ents - { - ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING(pTarget->pev->classname), targetName ); - pTarget->Use( pActivator, pCaller, useType, value ); - } - } -} - -LINK_ENTITY_TO_CLASS( DelayedUse, CBaseDelay ); - - -void CBaseDelay :: SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ) -{ - // - // exit immediatly if we don't have a target or kill target - // - if (FStringNull(pev->target) && !m_iszKillTarget) - return; - - // - // check for a delay - // - if (m_flDelay != 0) - { - // create a temp object to fire at a later time - CBaseDelay *pTemp = GetClassPtr( (CBaseDelay *)NULL); - pTemp->pev->classname = MAKE_STRING("DelayedUse"); - - pTemp->pev->nextthink = gpGlobals->time + m_flDelay; - - pTemp->SetThink( &CBaseDelay::DelayThink ); - - // Save the useType - pTemp->pev->button = (int)useType; - pTemp->m_iszKillTarget = m_iszKillTarget; - pTemp->m_flDelay = 0; // prevent "recursion" - pTemp->pev->target = pev->target; - - // HACKHACK - // This wasn't in the release build of Half-Life. We should have moved m_hActivator into this class - // but changing member variable hierarchy would break save/restore without some ugly code. - // This code is not as ugly as that code - if ( pActivator && pActivator->IsPlayer() ) // If a player activates, then save it - { - pTemp->pev->owner = pActivator->edict(); - } - else - { - pTemp->pev->owner = NULL; - } - - return; - } - - // - // kill the killtargets - // - - if ( m_iszKillTarget ) - { - edict_t *pentKillTarget = NULL; - - ALERT( at_aiconsole, "KillTarget: %s\n", STRING(m_iszKillTarget) ); - pentKillTarget = FIND_ENTITY_BY_TARGETNAME( NULL, STRING(m_iszKillTarget) ); - while ( !FNullEnt(pentKillTarget) ) - { - UTIL_Remove( CBaseEntity::Instance(pentKillTarget) ); - - ALERT( at_aiconsole, "killing %s\n", STRING( pentKillTarget->v.classname ) ); - pentKillTarget = FIND_ENTITY_BY_TARGETNAME( pentKillTarget, STRING(m_iszKillTarget) ); - } - } - - // - // fire targets - // - if (!FStringNull(pev->target)) - { - FireTargets( STRING(pev->target), pActivator, this, useType, value ); - } -} - - -/* -void CBaseDelay :: SUB_UseTargetsEntMethod( void ) -{ - SUB_UseTargets(pev); -} -*/ - -/* -QuakeEd only writes a single float for angles (bad idea), so up and down are -just constant angles. -*/ -void SetMovedir( entvars_t *pev ) -{ - if (pev->angles == Vector(0, -1, 0)) - { - pev->movedir = Vector(0, 0, 1); - } - else if (pev->angles == Vector(0, -2, 0)) - { - pev->movedir = Vector(0, 0, -1); - } - else - { - UTIL_MakeVectors(pev->angles); - pev->movedir = gpGlobals->v_forward; - } - - pev->angles = g_vecZero; -} - - - - -void CBaseDelay::DelayThink( void ) -{ - CBaseEntity *pActivator = NULL; - - if ( pev->owner != NULL ) // A player activated this on delay - { - pActivator = CBaseEntity::Instance( pev->owner ); - } - // The use type is cached (and stashed) in pev->button - SUB_UseTargets( pActivator, (USE_TYPE)pev->button, 0 ); - REMOVE_ENTITY(ENT(pev)); -} - - -// Global Savedata for Toggle -TYPEDESCRIPTION CBaseToggle::m_SaveData[] = -{ - DEFINE_FIELD( CBaseToggle, m_toggle_state, FIELD_INTEGER ), - DEFINE_FIELD( CBaseToggle, m_flActivateFinished, FIELD_TIME ), - DEFINE_FIELD( CBaseToggle, m_flMoveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flLip, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flTWidth, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_flTLength, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_vecPosition1, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecPosition2, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecAngle1, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? - DEFINE_FIELD( CBaseToggle, m_vecAngle2, FIELD_VECTOR ), // UNDONE: Position could go through transition, but also angle? - DEFINE_FIELD( CBaseToggle, m_cTriggersLeft, FIELD_INTEGER ), - DEFINE_FIELD( CBaseToggle, m_flHeight, FIELD_FLOAT ), - DEFINE_FIELD( CBaseToggle, m_hActivator, FIELD_EHANDLE ), - DEFINE_FIELD( CBaseToggle, m_pfnCallWhenMoveDone, FIELD_FUNCTION ), - DEFINE_FIELD( CBaseToggle, m_vecFinalDest, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_vecFinalAngle, FIELD_VECTOR ), - DEFINE_FIELD( CBaseToggle, m_sMaster, FIELD_STRING), - DEFINE_FIELD( CBaseToggle, m_bitsDamageInflict, FIELD_INTEGER ), // damage type inflicted -}; -IMPLEMENT_SAVERESTORE( CBaseToggle, CBaseAnimating ); - - -void CBaseToggle::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "lip")) - { - m_flLip = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "master")) - { - m_sMaster = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "distance")) - { - m_flMoveDistance = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - -/* -============= -LinearMove - -calculate pev->velocity and pev->nextthink to reach vecDest from -pev->origin traveling at flSpeed -=============== -*/ -void CBaseToggle :: LinearMove( Vector vecDest, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "LinearMove: no speed is defined!"); -// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "LinearMove: no post-move function defined"); - - m_vecFinalDest = vecDest; - - // Already there? - if (vecDest == pev->origin) - { - LinearMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDest - pev->origin; - - // divide vector length by speed to get time to reach dest - float flTravelTime = vecDestDelta.Length() / flSpeed; - - // set nextthink to trigger a call to LinearMoveDone when dest is reached - pev->nextthink = pev->ltime + flTravelTime; - SetThink( &CBaseToggle::LinearMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - pev->velocity = vecDestDelta / flTravelTime; -} - - -/* -============ -After moving, set origin to exact final destination, call "move done" function -============ -*/ -void CBaseToggle :: LinearMoveDone( void ) -{ - Vector delta = m_vecFinalDest - pev->origin; - float error = delta.Length(); - if ( error > 0.03125 ) - { - LinearMove( m_vecFinalDest, 100 ); - return; - } - - UTIL_SetOrigin(pev, m_vecFinalDest); - pev->velocity = g_vecZero; - pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); -} - -BOOL CBaseToggle :: IsLockedByMaster( void ) -{ - if (m_sMaster && !UTIL_IsMasterTriggered(m_sMaster, m_hActivator)) - return TRUE; - else - return FALSE; -} - -/* -============= -AngularMove - -calculate pev->velocity and pev->nextthink to reach vecDest from -pev->origin traveling at flSpeed -Just like LinearMove, but rotational. -=============== -*/ -void CBaseToggle :: AngularMove( Vector vecDestAngle, float flSpeed ) -{ - ASSERTSZ(flSpeed != 0, "AngularMove: no speed is defined!"); -// ASSERTSZ(m_pfnCallWhenMoveDone != NULL, "AngularMove: no post-move function defined"); - - m_vecFinalAngle = vecDestAngle; - - // Already there? - if (vecDestAngle == pev->angles) - { - AngularMoveDone(); - return; - } - - // set destdelta to the vector needed to move - Vector vecDestDelta = vecDestAngle - pev->angles; - - // divide by speed to get time to reach dest - float flTravelTime = vecDestDelta.Length() / flSpeed; - - // set nextthink to trigger a call to AngularMoveDone when dest is reached - pev->nextthink = pev->ltime + flTravelTime; - SetThink( &CBaseToggle::AngularMoveDone ); - - // scale the destdelta vector by the time spent traveling to get velocity - pev->avelocity = vecDestDelta / flTravelTime; -} - - -/* -============ -After rotating, set angle to exact final angle, call "move done" function -============ -*/ -void CBaseToggle :: AngularMoveDone( void ) -{ - pev->angles = m_vecFinalAngle; - pev->avelocity = g_vecZero; - pev->nextthink = -1; - if ( m_pfnCallWhenMoveDone ) - (this->*m_pfnCallWhenMoveDone)(); -} - - -float CBaseToggle :: AxisValue( int flags, const Vector &angles ) -{ - if ( FBitSet(flags, SF_DOOR_ROTATE_Z) ) - return angles.z; - if ( FBitSet(flags, SF_DOOR_ROTATE_X) ) - return angles.x; - - return angles.y; -} - - -void CBaseToggle :: AxisDir( entvars_t *pev ) -{ - if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_Z) ) - pev->movedir = Vector ( 0, 0, 1 ); // around z-axis - else if ( FBitSet(pev->spawnflags, SF_DOOR_ROTATE_X) ) - pev->movedir = Vector ( 1, 0, 0 ); // around x-axis - else - pev->movedir = Vector ( 0, 1, 0 ); // around y-axis -} - - -float CBaseToggle :: AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ) -{ - if ( FBitSet (flags, SF_DOOR_ROTATE_Z) ) - return angle1.z - angle2.z; - - if ( FBitSet (flags, SF_DOOR_ROTATE_X) ) - return angle1.x - angle2.x; - - return angle1.y - angle2.y; -} - - -/* -============= -FEntIsVisible - -returns TRUE if the passed entity is visible to caller, even if not infront () -============= -*/ - BOOL -FEntIsVisible( - entvars_t* pev, - entvars_t* pevTarget) - { - Vector vecSpot1 = pev->origin + pev->view_ofs; - Vector vecSpot2 = pevTarget->origin + pevTarget->view_ofs; - TraceResult tr; - - UTIL_TraceLine(vecSpot1, vecSpot2, ignore_monsters, ENT(pev), &tr); - - if (tr.fInOpen && tr.fInWater) - return FALSE; // sight line crossed contents - - if (tr.flFraction == 1) - return TRUE; - - return FALSE; - } - - diff --git a/sdk/dlls/talkmonster.cpp b/sdk/dlls/talkmonster.cpp deleted file mode 100644 index ab3b83b..0000000 --- a/sdk/dlls/talkmonster.cpp +++ /dev/null @@ -1,1467 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "talkmonster.h" -#include "defaultai.h" -#include "scripted.h" -#include "soundent.h" -#include "animation.h" - -//========================================================= -// Talking monster base class -// Used for scientists and barneys -//========================================================= -float CTalkMonster::g_talkWaitTime = 0; // time delay until it's ok to speak: used so that two NPCs don't talk at once - -// NOTE: m_voicePitch & m_szGrp should be fixed up by precache each save/restore - -TYPEDESCRIPTION CTalkMonster::m_SaveData[] = -{ - DEFINE_FIELD( CTalkMonster, m_bitsSaid, FIELD_INTEGER ), - DEFINE_FIELD( CTalkMonster, m_nSpeak, FIELD_INTEGER ), - - // Recalc'ed in Precache() - // DEFINE_FIELD( CTalkMonster, m_voicePitch, FIELD_INTEGER ), - // DEFINE_FIELD( CTalkMonster, m_szGrp, FIELD_??? ), - DEFINE_FIELD( CTalkMonster, m_useTime, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_iszUse, FIELD_STRING ), - DEFINE_FIELD( CTalkMonster, m_iszUnUse, FIELD_STRING ), - DEFINE_FIELD( CTalkMonster, m_flLastSaidSmelled, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_flStopTalkTime, FIELD_TIME ), - DEFINE_FIELD( CTalkMonster, m_hTalkTarget, FIELD_EHANDLE ), -}; - -IMPLEMENT_SAVERESTORE( CTalkMonster, CBaseMonster ); - -// array of friend names -const char *CTalkMonster::m_szFriends[TLK_CFRIENDS] = -{ - "monster_barney", - "monster_scientist", - "monster_sitting_scientist", -}; - - -//========================================================= -// AI Schedules Specific to talking monsters -//========================================================= - -Task_t tlIdleResponse[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_IDLE },// Stop and listen - { TASK_WAIT, (float)0.5 },// Wait until sure it's me they are talking to - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done - { TASK_TLK_RESPOND, (float)0 },// Wait and then say my response - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done -}; - -Schedule_t slIdleResponse[] = -{ - { - tlIdleResponse, - ARRAYSIZE ( tlIdleResponse ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Response" - - }, -}; - -Task_t tlIdleSpeak[] = -{ - { TASK_TLK_SPEAK, (float)0 },// question or remark - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT_RANDOM, (float)0.5 }, -}; - -Schedule_t slIdleSpeak[] = -{ - { - tlIdleSpeak, - ARRAYSIZE ( tlIdleSpeak ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Speak" - }, -}; - -Task_t tlIdleSpeakWait[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk - { TASK_TLK_SPEAK, (float)0 },// question or remark - { TASK_TLK_EYECONTACT, (float)0 },// - { TASK_WAIT, (float)2 },// wait - used when sci is in 'use' mode to keep head turned -}; - -Schedule_t slIdleSpeakWait[] = -{ - { - tlIdleSpeakWait, - ARRAYSIZE ( tlIdleSpeakWait ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "Idle Speak Wait" - }, -}; - -Task_t tlIdleHello[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 },// Stop and talk - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - { TASK_TLK_HELLO, (float)0 },// Try to say hello to player - { TASK_TLK_EYECONTACT, (float)0 }, - { TASK_WAIT, (float)0.5 },// wait a bit - -}; - -Schedule_t slIdleHello[] = -{ - { - tlIdleHello, - ARRAYSIZE ( tlIdleHello ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT, - "Idle Hello" - }, -}; - -Task_t tlIdleStopShooting[] = -{ - { TASK_TLK_STOPSHOOTING, (float)0 },// tell player to stop shooting friend - // { TASK_TLK_EYECONTACT, (float)0 },// look at the player -}; - -Schedule_t slIdleStopShooting[] = -{ - { - tlIdleStopShooting, - ARRAYSIZE ( tlIdleStopShooting ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - 0, - "Idle Stop Shooting" - }, -}; - -Task_t tlMoveAway[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_MOVE_AWAY_FAIL }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_MOVE_AWAY_PATH, (float)100 }, - { TASK_WALK_PATH_FOR_UNITS, (float)100 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_PLAYER, (float)0.5 }, -}; - -Schedule_t slMoveAway[] = -{ - { - tlMoveAway, - ARRAYSIZE ( tlMoveAway ), - 0, - 0, - "MoveAway" - }, -}; - - -Task_t tlMoveAwayFail[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_PLAYER, (float)0.5 }, -}; - -Schedule_t slMoveAwayFail[] = -{ - { - tlMoveAwayFail, - ARRAYSIZE ( tlMoveAwayFail ), - 0, - 0, - "MoveAwayFail" - }, -}; - - - -Task_t tlMoveAwayFollow[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TARGET_FACE }, - { TASK_STORE_LASTPOSITION, (float)0 }, - { TASK_MOVE_AWAY_PATH, (float)100 }, - { TASK_WALK_PATH_FOR_UNITS, (float)100 }, - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slMoveAwayFollow[] = -{ - { - tlMoveAwayFollow, - ARRAYSIZE ( tlMoveAwayFollow ), - 0, - 0, - "MoveAwayFollow" - }, -}; - -Task_t tlTlkIdleWatchClient[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_TLK_LOOK_AT_CLIENT, (float)6 }, -}; - -Task_t tlTlkIdleWatchClientStare[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_TLK_CLIENT_STARE, (float)6 }, - { TASK_TLK_STARE, (float)0 }, - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 }, -}; - -Schedule_t slTlkIdleWatchClient[] = -{ - { - tlTlkIdleWatchClient, - ARRAYSIZE ( tlTlkIdleWatchClient ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_CLIENT_UNSEEN | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "TlkIdleWatchClient" - }, - - { - tlTlkIdleWatchClientStare, - ARRAYSIZE ( tlTlkIdleWatchClientStare ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SMELL | - bits_COND_CLIENT_PUSH | - bits_COND_CLIENT_UNSEEN | - bits_COND_PROVOKED, - - bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code. - //bits_SOUND_PLAYER | - //bits_SOUND_WORLD | - - bits_SOUND_DANGER | - bits_SOUND_MEAT |// scents - bits_SOUND_CARCASS | - bits_SOUND_GARBAGE, - "TlkIdleWatchClientStare" - }, -}; - - -Task_t tlTlkIdleEyecontact[] = -{ - { TASK_TLK_IDEALYAW, (float)0 },// look at who I'm talking to - { TASK_FACE_IDEAL, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_SIGNAL3 }, - { TASK_TLK_EYECONTACT, (float)0 },// Wait until speaker is done -}; - -Schedule_t slTlkIdleEyecontact[] = -{ - { - tlTlkIdleEyecontact, - ARRAYSIZE ( tlTlkIdleEyecontact ), - bits_COND_NEW_ENEMY | - bits_COND_CLIENT_PUSH | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "TlkIdleEyecontact" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CTalkMonster ) -{ - slIdleResponse, - slIdleSpeak, - slIdleHello, - slIdleSpeakWait, - slIdleStopShooting, - slMoveAway, - slMoveAwayFollow, - slMoveAwayFail, - slTlkIdleWatchClient, - &slTlkIdleWatchClient[ 1 ], - slTlkIdleEyecontact, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CTalkMonster, CBaseMonster ); - - -void CTalkMonster :: SetActivity ( Activity newActivity ) -{ - if (newActivity == ACT_IDLE && IsTalking() ) - newActivity = ACT_SIGNAL3; - - if ( newActivity == ACT_SIGNAL3 && (LookupActivity ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE)) - newActivity = ACT_IDLE; - - CBaseMonster::SetActivity( newActivity ); -} - - -void CTalkMonster :: StartTask( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TLK_SPEAK: - // ask question or make statement - FIdleSpeak(); - TaskComplete(); - break; - - case TASK_TLK_RESPOND: - // respond to question - IdleRespond(); - TaskComplete(); - break; - - case TASK_TLK_HELLO: - // greet player - FIdleHello(); - TaskComplete(); - break; - - - case TASK_TLK_STARE: - // let the player know I know he's staring at me. - FIdleStare(); - TaskComplete(); - break; - - case TASK_FACE_PLAYER: - case TASK_TLK_LOOK_AT_CLIENT: - case TASK_TLK_CLIENT_STARE: - // track head to the client for a while. - m_flWaitFinished = gpGlobals->time + pTask->flData; - break; - - case TASK_TLK_EYECONTACT: - break; - - case TASK_TLK_IDEALYAW: - if (m_hTalkTarget != 0) - { - pev->yaw_speed = 60; - float yaw = VecToYaw(m_hTalkTarget->pev->origin - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - if (yaw < 0) - { - pev->ideal_yaw = min( yaw + 45, 0 ) + pev->angles.y; - } - else - { - pev->ideal_yaw = max( yaw - 45, 0 ) + pev->angles.y; - } - } - TaskComplete(); - break; - - case TASK_TLK_HEADRESET: - // reset head position after looking at something - m_hTalkTarget = NULL; - TaskComplete(); - break; - - case TASK_TLK_STOPSHOOTING: - // tell player to stop shooting - PlaySentence( m_szGrp[TLK_NOSHOOT], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_NORM ); - TaskComplete(); - break; - - case TASK_CANT_FOLLOW: - StopFollowing( FALSE ); - PlaySentence( m_szGrp[TLK_STOP], RANDOM_FLOAT(2, 2.5), VOL_NORM, ATTN_NORM ); - TaskComplete(); - break; - - case TASK_WALK_PATH_FOR_UNITS: - m_movementActivity = ACT_WALK; - break; - - case TASK_MOVE_AWAY_PATH: - { - Vector dir = pev->angles; - dir.y = pev->ideal_yaw + 180; - Vector move; - - UTIL_MakeVectorsPrivate( dir, move, NULL, NULL ); - dir = pev->origin + move * pTask->flData; - if ( MoveToLocation( ACT_WALK, 2, dir ) ) - { - TaskComplete(); - } - else if ( FindCover( pev->origin, pev->view_ofs, 0, CoverRadius() ) ) - { - // then try for plain ole cover - m_flMoveWaitFinished = gpGlobals->time + 2; - TaskComplete(); - } - else - { - // nowhere to go? - TaskFail(); - } - } - break; - - case TASK_PLAY_SCRIPT: - m_hTalkTarget = NULL; - CBaseMonster::StartTask( pTask ); - break; - - default: - CBaseMonster::StartTask( pTask ); - } -} - - -void CTalkMonster :: RunTask( Task_t *pTask ) -{ - switch( pTask->iTask ) - { - case TASK_TLK_CLIENT_STARE: - case TASK_TLK_LOOK_AT_CLIENT: - - edict_t *pPlayer; - - // track head to the client for a while. - if ( m_MonsterState == MONSTERSTATE_IDLE && - !IsMoving() && - !IsTalking() ) - { - // Get edict for one player - pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - IdleHeadTurn( pPlayer->v.origin ); - } - } - else - { - // started moving or talking - TaskFail(); - return; - } - - if ( pTask->iTask == TASK_TLK_CLIENT_STARE ) - { - // fail out if the player looks away or moves away. - if ( ( pPlayer->v.origin - pev->origin ).Length2D() > TLK_STARE_DIST ) - { - // player moved away. - TaskFail(); - } - - UTIL_MakeVectors( pPlayer->v.angles ); - if ( UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) < m_flFieldOfView ) - { - // player looked away - TaskFail(); - } - } - - if ( gpGlobals->time > m_flWaitFinished ) - { - TaskComplete(); - } - break; - - case TASK_FACE_PLAYER: - { - // Get edict for one player - edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - MakeIdealYaw ( pPlayer->v.origin ); - ChangeYaw ( pev->yaw_speed ); - IdleHeadTurn( pPlayer->v.origin ); - if ( gpGlobals->time > m_flWaitFinished && FlYawDiff() < 10 ) - { - TaskComplete(); - } - } - else - { - TaskFail(); - } - } - break; - - case TASK_TLK_EYECONTACT: - if (!IsMoving() && IsTalking() && m_hTalkTarget != 0) - { - // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - TaskComplete(); - } - break; - - case TASK_WALK_PATH_FOR_UNITS: - { - float distance; - - distance = (m_vecLastPosition - pev->origin).Length2D(); - - // Walk path until far enough away - if ( distance > pTask->flData || MovementIsComplete() ) - { - TaskComplete(); - RouteClear(); // Stop moving - } - } - break; - case TASK_WAIT_FOR_MOVEMENT: - if (IsTalking() && m_hTalkTarget != 0) - { - // ALERT(at_console, "walking, talking\n"); - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - IdleHeadTurn( pev->origin ); - // override so that during walk, a scientist may talk and greet player - FIdleHello(); - if (RANDOM_LONG(0,m_nSpeak * 20) == 0) - { - FIdleSpeak(); - } - } - - CBaseMonster::RunTask( pTask ); - if (TaskIsComplete()) - IdleHeadTurn( pev->origin ); - break; - - default: - if (IsTalking() && m_hTalkTarget != 0) - { - IdleHeadTurn( m_hTalkTarget->pev->origin ); - } - else - { - SetBoneController( 0, 0 ); - } - CBaseMonster::RunTask( pTask ); - } -} - - -void CTalkMonster :: Killed( entvars_t *pevAttacker, int iGib ) -{ - // If a client killed me (unless I was already Barnacle'd), make everyone else mad/afraid of him - if ( (pevAttacker->flags & FL_CLIENT) && m_MonsterState != MONSTERSTATE_PRONE ) - { - AlertFriends(); - LimitFollowers( CBaseEntity::Instance(pevAttacker), 0 ); - } - - m_hTargetEnt = NULL; - // Don't finish that sentence - StopTalking(); - SetUse( NULL ); - CBaseMonster::Killed( pevAttacker, iGib ); -} - - - -CBaseEntity *CTalkMonster::EnumFriends( CBaseEntity *pPrevious, int listNumber, BOOL bTrace ) -{ - CBaseEntity *pFriend = pPrevious; - const char *pszFriend; - TraceResult tr; - Vector vecCheck; - - pszFriend = m_szFriends[ FriendNumber(listNumber) ]; - while ((pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ))) - { - if (pFriend == this || !pFriend->IsAlive()) - // don't talk to self or dead people - continue; - if ( bTrace ) - { - vecCheck = pFriend->pev->origin; - vecCheck.z = pFriend->pev->absmax.z; - - UTIL_TraceLine( pev->origin, vecCheck, ignore_monsters, ENT(pev), &tr); - } - else - tr.flFraction = 1.0; - - if (tr.flFraction == 1.0) - { - return pFriend; - } - } - - return NULL; -} - - -void CTalkMonster::AlertFriends( void ) -{ - CBaseEntity *pFriend = NULL; - int i; - - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while ((pFriend = EnumFriends( pFriend, i, TRUE ))) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster->IsAlive() ) - { - // don't provoke a friend that's playing a death animation. They're a goner - pMonster->m_afMemory |= bits_MEMORY_PROVOKED; - } - } - } -} - - - -void CTalkMonster::ShutUpFriends( void ) -{ - CBaseEntity *pFriend = NULL; - int i; - - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while ((pFriend = EnumFriends( pFriend, i, TRUE ))) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) - { - pMonster->SentenceStop(); - } - } - } -} - - -// UNDONE: Keep a follow time in each follower, make a list of followers in this function and do LRU -// UNDONE: Check this in Restore to keep restored monsters from joining a full list of followers -void CTalkMonster::LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ) -{ - CBaseEntity *pFriend = NULL; - int i, count; - - count = 0; - // for each friend in this bsp... - for ( i = 0; i < TLK_CFRIENDS; i++ ) - { - while ((pFriend = EnumFriends( pFriend, i, FALSE ))) - { - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - if ( pMonster ) - { - if ( pMonster->m_hTargetEnt == pPlayer ) - { - count++; - if ( count > maxFollowers ) - pMonster->StopFollowing( TRUE ); - } - } - } - } -} - - -float CTalkMonster::TargetDistance( void ) -{ - // If we lose the player, or he dies, return a really large distance - if ( m_hTargetEnt == 0 || !m_hTargetEnt->IsAlive() ) - return 1e6; - - return (m_hTargetEnt->pev->origin - pev->origin).Length(); -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CTalkMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case SCRIPT_EVENT_SENTENCE_RND1: // Play a named sentence group 25% of the time - if (RANDOM_LONG(0,99) < 75) - break; - // fall through... - case SCRIPT_EVENT_SENTENCE: // Play a named sentence group - ShutUpFriends(); - PlaySentence( pEvent->options, RANDOM_FLOAT(2.8, 3.4), VOL_NORM, ATTN_IDLE ); - //ALERT(at_console, "script event speak\n"); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -// monsters derived from ctalkmonster should call this in precache() - -void CTalkMonster :: TalkInit( void ) -{ - // every new talking monster must reset this global, otherwise - // when a level is loaded, nobody will talk (time is reset to 0) - - CTalkMonster::g_talkWaitTime = 0; - - m_voicePitch = 100; -} -//========================================================= -// FindNearestFriend -// Scan for nearest, visible friend. If fPlayer is true, look for -// nearest player -//========================================================= -CBaseEntity *CTalkMonster :: FindNearestFriend(BOOL fPlayer) -{ - CBaseEntity *pFriend = NULL; - CBaseEntity *pNearest = NULL; - float range = 10000000.0; - TraceResult tr; - Vector vecStart = pev->origin; - Vector vecCheck; - int i; - const char *pszFriend; - int cfriends; - - vecStart.z = pev->absmax.z; - - if (fPlayer) - cfriends = 1; - else - cfriends = TLK_CFRIENDS; - - // for each type of friend... - - for (i = cfriends-1; i > -1; i--) - { - if (fPlayer) - pszFriend = "player"; - else - pszFriend = m_szFriends[FriendNumber(i)]; - - if (!pszFriend) - continue; - - // for each friend in this bsp... - while ((pFriend = UTIL_FindEntityByClassname( pFriend, pszFriend ))) - { - if (pFriend == this || !pFriend->IsAlive()) - // don't talk to self or dead people - continue; - - CBaseMonster *pMonster = pFriend->MyMonsterPointer(); - - // If not a monster for some reason, or in a script, or prone - if ( !pMonster || pMonster->m_MonsterState == MONSTERSTATE_SCRIPT || pMonster->m_MonsterState == MONSTERSTATE_PRONE ) - continue; - - vecCheck = pFriend->pev->origin; - vecCheck.z = pFriend->pev->absmax.z; - - // if closer than previous friend, and in range, see if he's visible - - if (range > (vecStart - vecCheck).Length()) - { - UTIL_TraceLine(vecStart, vecCheck, ignore_monsters, ENT(pev), &tr); - - if (tr.flFraction == 1.0) - { - // visible and in range, this is the new nearest scientist - if ((vecStart - vecCheck).Length() < TALKRANGE_MIN) - { - pNearest = pFriend; - range = (vecStart - vecCheck).Length(); - } - } - } - } - } - return pNearest; -} - -int CTalkMonster :: GetVoicePitch( void ) -{ - return m_voicePitch + RANDOM_LONG(0,3); -} - - -void CTalkMonster :: Touch( CBaseEntity *pOther ) -{ - // Did the player touch me? - if ( pOther->IsPlayer() ) - { - // Ignore if pissed at player - if ( m_afMemory & bits_MEMORY_PROVOKED ) - return; - - // Stay put during speech - if ( IsTalking() ) - return; - - // Heuristic for determining if the player is pushing me away - float speed = fabs(pOther->pev->velocity.x) + fabs(pOther->pev->velocity.y); - if ( speed > 50 ) - { - SetConditions( bits_COND_CLIENT_PUSH ); - MakeIdealYaw( pOther->pev->origin ); - } - } -} - - - -//========================================================= -// IdleRespond -// Respond to a previous question -//========================================================= -void CTalkMonster :: IdleRespond( void ) -{ - // play response - PlaySentence( m_szGrp[TLK_ANSWER], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); -} - -int CTalkMonster :: FOkToSpeak( void ) -{ - // if in the grip of a barnacle, don't speak - if ( m_MonsterState == MONSTERSTATE_PRONE || m_IdealMonsterState == MONSTERSTATE_PRONE ) - { - return FALSE; - } - - // if not alive, certainly don't speak - if ( pev->deadflag != DEAD_NO ) - { - return FALSE; - } - - // if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - return FALSE; - - if ( m_MonsterState == MONSTERSTATE_PRONE ) - return FALSE; - - // if player is not in pvs, don't speak - if (!IsAlive() || FNullEnt(FIND_CLIENT_IN_PVS(edict()))) - return FALSE; - - // don't talk if you're in combat - if (m_hEnemy != 0 && FVisible( m_hEnemy )) - return FALSE; - - return TRUE; -} - - -int CTalkMonster::CanPlaySentence( BOOL fDisregardState ) -{ - if ( fDisregardState ) - return CBaseMonster::CanPlaySentence( fDisregardState ); - return FOkToSpeak(); -} - -//========================================================= -// FIdleStare -//========================================================= -int CTalkMonster :: FIdleStare( void ) -{ - if (!FOkToSpeak()) - return FALSE; - - PlaySentence( m_szGrp[TLK_STARE], RANDOM_FLOAT(5, 7.5), VOL_NORM, ATTN_IDLE ); - - m_hTalkTarget = FindNearestFriend( TRUE ); - return TRUE; -} - -//========================================================= -// IdleHello -// Try to greet player first time he's seen -//========================================================= -int CTalkMonster :: FIdleHello( void ) -{ - if (!FOkToSpeak()) - return FALSE; - - // if this is first time scientist has seen player, greet him - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - { - // get a player - CBaseEntity *pPlayer = FindNearestFriend(TRUE); - - if (pPlayer) - { - if (FInViewCone(pPlayer) && FVisible(pPlayer)) - { - m_hTalkTarget = pPlayer; - - if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) - PlaySentence( m_szGrp[TLK_PHELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); - else - PlaySentence( m_szGrp[TLK_HELLO], RANDOM_FLOAT(3, 3.5), VOL_NORM, ATTN_IDLE ); - - SetBits(m_bitsSaid, bit_saidHelloPlayer); - - return TRUE; - } - } - } - return FALSE; -} - - -// turn head towards supplied origin -void CTalkMonster :: IdleHeadTurn( Vector &vecFriend ) -{ - // turn head in desired direction only if ent has a turnable head - if (m_afCapability & bits_CAP_TURN_HEAD) - { - float yaw = VecToYaw(vecFriend - pev->origin) - pev->angles.y; - - if (yaw > 180) yaw -= 360; - if (yaw < -180) yaw += 360; - - // turn towards vector - SetBoneController( 0, yaw ); - } -} - -//========================================================= -// FIdleSpeak -// ask question of nearby friend, or make statement -//========================================================= -int CTalkMonster :: FIdleSpeak ( void ) -{ - // try to start a conversation, or make statement - const char *szIdleGroup; - const char *szQuestionGroup; - float duration; - - if (!FOkToSpeak()) - return FALSE; - - // set idle groups based on pre/post disaster - if (FBitSet(pev->spawnflags, SF_MONSTER_PREDISASTER)) - { - szIdleGroup = m_szGrp[TLK_PIDLE]; - szQuestionGroup = m_szGrp[TLK_PQUESTION]; - // set global min delay for next conversation - duration = RANDOM_FLOAT(4.8, 5.2); - } - else - { - szIdleGroup = m_szGrp[TLK_IDLE]; - szQuestionGroup = m_szGrp[TLK_QUESTION]; - // set global min delay for next conversation - duration = RANDOM_FLOAT(2.8, 3.2); - - } - - // player using this entity is alive and wounded? - CBaseEntity *pTarget = m_hTargetEnt; - - if ( pTarget != NULL ) - { - if ( pTarget->IsPlayer() ) - { - if ( pTarget->IsAlive() ) - { - m_hTalkTarget = m_hTargetEnt; - if (!FBitSet(m_bitsSaid, bit_saidDamageHeavy) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 8)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT3], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT3], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageHeavy); - return TRUE; - } - else if (!FBitSet(m_bitsSaid, bit_saidDamageMedium) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 4)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT2], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT2], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageMedium); - return TRUE; - } - else if (!FBitSet(m_bitsSaid, bit_saidDamageLight) && - (m_hTargetEnt->pev->health <= m_hTargetEnt->pev->max_health / 2)) - { - //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, m_szGrp[TLK_PLHURT1], 1.0, ATTN_IDLE, 0, pitch); - PlaySentence( m_szGrp[TLK_PLHURT1], duration, VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidDamageLight); - return TRUE; - } - } - else - { - //!!!KELLY - here's a cool spot to have the talkmonster talk about the dead player if we want. - // "Oh dear, Gordon Freeman is dead!" -Scientist - // "Damn, I can't do this without you." -Barney - } - } - } - - // if there is a friend nearby to speak to, play sentence, set friend's response time, return - CBaseEntity *pFriend = FindNearestFriend(FALSE); - - if (pFriend && !(pFriend->IsMoving()) && (RANDOM_LONG(0,99) < 75)) - { - PlaySentence( szQuestionGroup, duration, VOL_NORM, ATTN_IDLE ); - //SENTENCEG_PlayRndSz( ENT(pev), szQuestionGroup, 1.0, ATTN_IDLE, 0, pitch ); - - // force friend to answer - CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; - m_hTalkTarget = pFriend; - pTalkMonster->SetAnswerQuestion( this ); // UNDONE: This is EVIL!!! - pTalkMonster->m_flStopTalkTime = m_flStopTalkTime; - - m_nSpeak++; - return TRUE; - } - - // otherwise, play an idle statement, try to face client when making a statement. - if ( RANDOM_LONG(0,1) ) - { - //SENTENCEG_PlayRndSz( ENT(pev), szIdleGroup, 1.0, ATTN_IDLE, 0, pitch ); - CBaseEntity *pFriend = FindNearestFriend(TRUE); - - if ( pFriend ) - { - m_hTalkTarget = pFriend; - PlaySentence( szIdleGroup, duration, VOL_NORM, ATTN_IDLE ); - m_nSpeak++; - return TRUE; - } - } - - // didn't speak - Talk( 0 ); - CTalkMonster::g_talkWaitTime = 0; - return FALSE; -} - -void CTalkMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) -{ - if ( !bConcurrent ) - ShutUpFriends(); - - ClearConditions( bits_COND_CLIENT_PUSH ); // Forget about moving! I've got something to say! - m_useTime = gpGlobals->time + duration; - PlaySentence( pszSentence, duration, volume, attenuation ); - - m_hTalkTarget = pListener; -} - -void CTalkMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) -{ - if ( !pszSentence ) - return; - - Talk ( duration ); - - CTalkMonster::g_talkWaitTime = gpGlobals->time + duration + 2.0; - if ( pszSentence[0] == '!' ) - EMIT_SOUND_DYN( edict(), CHAN_VOICE, pszSentence, volume, attenuation, 0, GetVoicePitch()); - else - SENTENCEG_PlayRndSz( edict(), pszSentence, volume, attenuation, 0, GetVoicePitch() ); - - // If you say anything, don't greet the player - you may have already spoken to them - SetBits(m_bitsSaid, bit_saidHelloPlayer); -} - -//========================================================= -// Talk - set a timer that tells us when the monster is done -// talking. -//========================================================= -void CTalkMonster :: Talk( float flDuration ) -{ - if ( flDuration <= 0 ) - { - // no duration :( - m_flStopTalkTime = gpGlobals->time + 3; - } - else - { - m_flStopTalkTime = gpGlobals->time + flDuration; - } -} - -// Prepare this talking monster to answer question -void CTalkMonster :: SetAnswerQuestion( CTalkMonster *pSpeaker ) -{ - if ( !m_pCine ) - ChangeSchedule( slIdleResponse ); - m_hTalkTarget = (CBaseMonster *)pSpeaker; -} - -int CTalkMonster :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) -{ - if ( IsAlive() ) - { - // if player damaged this entity, have other friends talk about it - if (pevAttacker && m_MonsterState != MONSTERSTATE_PRONE && FBitSet(pevAttacker->flags, FL_CLIENT)) - { - CBaseEntity *pFriend = FindNearestFriend(FALSE); - - if (pFriend && pFriend->IsAlive()) - { - // only if not dead or dying! - CTalkMonster *pTalkMonster = (CTalkMonster *)pFriend; - pTalkMonster->ChangeSchedule( slIdleStopShooting ); - } - } - } - return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -Schedule_t* CTalkMonster :: GetScheduleOfType ( int Type ) -{ - switch( Type ) - { - case SCHED_MOVE_AWAY: - return slMoveAway; - - case SCHED_MOVE_AWAY_FOLLOW: - return slMoveAwayFollow; - - case SCHED_MOVE_AWAY_FAIL: - return slMoveAwayFail; - - case SCHED_TARGET_FACE: - // speak during 'use' - if (RANDOM_LONG(0,99) < 2) - //ALERT ( at_console, "target chase speak\n" ); - return slIdleSpeakWait; - else - return slIdleStand; - - case SCHED_IDLE_STAND: - { - // if never seen player, try to greet him - if (!FBitSet(m_bitsSaid, bit_saidHelloPlayer)) - { - return slIdleHello; - } - - // sustained light wounds? - if (!FBitSet(m_bitsSaid, bit_saidWoundLight) && (pev->health <= (pev->max_health * 0.75))) - { - //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_WOUND], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); - //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); - PlaySentence( m_szGrp[TLK_WOUND], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidWoundLight); - return slIdleStand; - } - // sustained heavy wounds? - else if (!FBitSet(m_bitsSaid, bit_saidWoundHeavy) && (pev->health <= (pev->max_health * 0.5))) - { - //SENTENCEG_PlayRndSz( ENT(pev), m_szGrp[TLK_MORTAL], 1.0, ATTN_IDLE, 0, GetVoicePitch() ); - //CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(2.8, 3.2); - PlaySentence( m_szGrp[TLK_MORTAL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - SetBits(m_bitsSaid, bit_saidWoundHeavy); - return slIdleStand; - } - - // talk about world - if (FOkToSpeak() && RANDOM_LONG(0,m_nSpeak * 2) == 0) - { - //ALERT ( at_console, "standing idle speak\n" ); - return slIdleSpeak; - } - - if ( !IsTalking() && HasConditions ( bits_COND_SEE_CLIENT ) && RANDOM_LONG( 0, 6 ) == 0 ) - { - edict_t *pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - if ( pPlayer ) - { - // watch the client. - UTIL_MakeVectors ( pPlayer->v.angles ); - if ( ( pPlayer->v.origin - pev->origin ).Length2D() < TLK_STARE_DIST && - UTIL_DotPoints( pPlayer->v.origin, pev->origin, gpGlobals->v_forward ) >= m_flFieldOfView ) - { - // go into the special STARE schedule if the player is close, and looking at me too. - return &slTlkIdleWatchClient[ 1 ]; - } - - return slTlkIdleWatchClient; - } - } - else - { - if (IsTalking()) - // look at who we're talking to - return slTlkIdleEyecontact; - else - // regular standing idle - return slIdleStand; - } - - - // NOTE - caller must first CTalkMonster::GetScheduleOfType, - // then check result and decide what to return ie: if sci gets back - // slIdleStand, return slIdleSciStand - } - break; - } - - return CBaseMonster::GetScheduleOfType( Type ); -} - -//========================================================= -// IsTalking - am I saying a sentence right now? -//========================================================= -BOOL CTalkMonster :: IsTalking( void ) -{ - if ( m_flStopTalkTime > gpGlobals->time ) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// If there's a player around, watch him. -//========================================================= -void CTalkMonster :: PrescheduleThink ( void ) -{ - if ( !HasConditions ( bits_COND_SEE_CLIENT ) ) - { - SetConditions ( bits_COND_CLIENT_UNSEEN ); - } -} - -// try to smell something -void CTalkMonster :: TrySmellTalk( void ) -{ - if ( !FOkToSpeak() ) - return; - - // clear smell bits periodically - if ( gpGlobals->time > m_flLastSaidSmelled ) - { -// ALERT ( at_aiconsole, "Clear smell bits\n" ); - ClearBits(m_bitsSaid, bit_saidSmelled); - } - // smelled something? - if (!FBitSet(m_bitsSaid, bit_saidSmelled) && HasConditions ( bits_COND_SMELL )) - { - PlaySentence( m_szGrp[TLK_SMELL], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_flLastSaidSmelled = gpGlobals->time + 60;// don't talk about the stinky for a while. - SetBits(m_bitsSaid, bit_saidSmelled); - } -} - - - -int CTalkMonster::IRelationship( CBaseEntity *pTarget ) -{ - if ( pTarget->IsPlayer() ) - if ( m_afMemory & bits_MEMORY_PROVOKED ) - return R_HT; - return CBaseMonster::IRelationship( pTarget ); -} - - -void CTalkMonster::StopFollowing( BOOL clearSchedule ) -{ - if ( IsFollowing() ) - { - if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) - { - PlaySentence( m_szGrp[TLK_UNUSE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_hTalkTarget = m_hTargetEnt; - } - - if ( m_movementGoal == MOVEGOAL_TARGETENT ) - RouteClear(); // Stop him from walking toward the player - m_hTargetEnt = 0; - if ( clearSchedule ) - ClearSchedule(); - if ( m_hEnemy != 0 ) - m_IdealMonsterState = MONSTERSTATE_COMBAT; - } -} - - -void CTalkMonster::StartFollowing( CBaseEntity *pLeader ) -{ - if ( m_pCine ) - m_pCine->CancelScript(); - - if ( m_hEnemy != 0 ) - m_IdealMonsterState = MONSTERSTATE_ALERT; - - m_hTargetEnt = pLeader; - PlaySentence( m_szGrp[TLK_USE], RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); - m_hTalkTarget = m_hTargetEnt; - ClearConditions( bits_COND_CLIENT_PUSH ); - ClearSchedule(); -} - - -BOOL CTalkMonster::CanFollow( void ) -{ - if ( m_MonsterState == MONSTERSTATE_SCRIPT ) - { - if ( !m_pCine->CanInterrupt() ) - return FALSE; - } - - if ( !IsAlive() ) - return FALSE; - - return !IsFollowing(); -} - - -void CTalkMonster :: FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Don't allow use during a scripted_sentence - if ( m_useTime > gpGlobals->time ) - return; - - if ( pCaller != NULL && pCaller->IsPlayer() ) - { - // Pre-disaster followers can't be used - if ( pev->spawnflags & SF_MONSTER_PREDISASTER ) - { - DeclineFollowing(); - } - else if ( CanFollow() ) - { - LimitFollowers( pCaller , 1 ); - - if ( m_afMemory & bits_MEMORY_PROVOKED ) - ALERT( at_console, "I'm not following you, you evil person!\n" ); - else - { - StartFollowing( pCaller ); - SetBits(m_bitsSaid, bit_saidHelloPlayer); // Don't say hi after you've started following - } - } - else - { - StopFollowing( TRUE ); - } - } -} - -void CTalkMonster::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "UseSentence")) - { - m_iszUse = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "UnUseSentence")) - { - m_iszUnUse = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CTalkMonster::Precache( void ) -{ - if ( m_iszUse ) - m_szGrp[TLK_USE] = STRING( m_iszUse ); - if ( m_iszUnUse ) - m_szGrp[TLK_UNUSE] = STRING( m_iszUnUse ); -} - diff --git a/sdk/dlls/talkmonster.h b/sdk/dlls/talkmonster.h deleted file mode 100644 index 834c1da..0000000 --- a/sdk/dlls/talkmonster.h +++ /dev/null @@ -1,183 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef TALKMONSTER_H -#define TALKMONSTER_H - -#ifndef MONSTERS_H -#include "monsters.h" -#endif - -//========================================================= -// Talking monster base class -// Used for scientists and barneys -//========================================================= - -#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this - -#define TLK_STARE_DIST 128 // anyone closer than this and looking at me is probably staring at me. - -#define bit_saidDamageLight (1<<0) // bits so we don't repeat key sentences -#define bit_saidDamageMedium (1<<1) -#define bit_saidDamageHeavy (1<<2) -#define bit_saidHelloPlayer (1<<3) -#define bit_saidWoundLight (1<<4) -#define bit_saidWoundHeavy (1<<5) -#define bit_saidHeard (1<<6) -#define bit_saidSmelled (1<<7) - -#define TLK_CFRIENDS 3 - -typedef enum -{ - TLK_ANSWER = 0, - TLK_QUESTION, - TLK_IDLE, - TLK_STARE, - TLK_USE, - TLK_UNUSE, - TLK_STOP, - TLK_NOSHOOT, - TLK_HELLO, - TLK_PHELLO, - TLK_PIDLE, - TLK_PQUESTION, - TLK_PLHURT1, - TLK_PLHURT2, - TLK_PLHURT3, - TLK_SMELL, - TLK_WOUND, - TLK_MORTAL, - - TLK_CGROUPS, // MUST be last entry -} TALKGROUPNAMES; - - -enum -{ - SCHED_CANT_FOLLOW = LAST_COMMON_SCHEDULE + 1, - SCHED_MOVE_AWAY, // Try to get out of the player's way - SCHED_MOVE_AWAY_FOLLOW, // same, but follow afterward - SCHED_MOVE_AWAY_FAIL, // Turn back toward player - - LAST_TALKMONSTER_SCHEDULE, // MUST be last -}; - -enum -{ - TASK_CANT_FOLLOW = LAST_COMMON_TASK + 1, - TASK_MOVE_AWAY_PATH, - TASK_WALK_PATH_FOR_UNITS, - - TASK_TLK_RESPOND, // say my response - TASK_TLK_SPEAK, // question or remark - TASK_TLK_HELLO, // Try to say hello to player - TASK_TLK_HEADRESET, // reset head position - TASK_TLK_STOPSHOOTING, // tell player to stop shooting friend - TASK_TLK_STARE, // let the player know I know he's staring at me. - TASK_TLK_LOOK_AT_CLIENT,// faces player if not moving and not talking and in idle. - TASK_TLK_CLIENT_STARE, // same as look at client, but says something if the player stares. - TASK_TLK_EYECONTACT, // maintain eyecontact with person who I'm talking to - TASK_TLK_IDEALYAW, // set ideal yaw to face who I'm talking to - TASK_FACE_PLAYER, // Face the player - - LAST_TALKMONSTER_TASK, // MUST be last -}; - -class CTalkMonster : public CBaseMonster -{ -public: - void TalkInit( void ); - CBaseEntity *FindNearestFriend(BOOL fPlayer); - float TargetDistance( void ); - void StopTalking( void ) { SentenceStop(); } - - // Base Monster functions - void Precache( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - void Touch( CBaseEntity *pOther ); - void Killed( entvars_t *pevAttacker, int iGib ); - int IRelationship ( CBaseEntity *pTarget ); - virtual int CanPlaySentence( BOOL fDisregardState ); - virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); - void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); - void KeyValue( KeyValueData *pkvd ); - - // AI functions - void SetActivity ( Activity newActivity ); - Schedule_t *GetScheduleOfType ( int Type ); - void StartTask( Task_t *pTask ); - void RunTask( Task_t *pTask ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void PrescheduleThink( void ); - - - // Conversations / communication - int GetVoicePitch( void ); - void IdleRespond( void ); - int FIdleSpeak( void ); - int FIdleStare( void ); - int FIdleHello( void ); - void IdleHeadTurn( Vector &vecFriend ); - int FOkToSpeak( void ); - void TrySmellTalk( void ); - CBaseEntity *EnumFriends( CBaseEntity *pentPrevious, int listNumber, BOOL bTrace ); - void AlertFriends( void ); - void ShutUpFriends( void ); - BOOL IsTalking( void ); - void Talk( float flDuration ); - // For following - BOOL CanFollow( void ); - BOOL IsFollowing( void ) { return m_hTargetEnt != 0 && m_hTargetEnt->IsPlayer(); } - void StopFollowing( BOOL clearSchedule ); - void StartFollowing( CBaseEntity *pLeader ); - virtual void DeclineFollowing( void ) {} - void LimitFollowers( CBaseEntity *pPlayer, int maxFollowers ); - - void EXPORT FollowerUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void SetAnswerQuestion( CTalkMonster *pSpeaker ); - virtual int FriendNumber( int arrayNumber ) { return arrayNumber; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - - static const char *m_szFriends[TLK_CFRIENDS]; // array of friend names - static float g_talkWaitTime; - - int m_bitsSaid; // set bits for sentences we don't want repeated - int m_nSpeak; // number of times initiated talking - int m_voicePitch; // pitch of voice for this head - const char *m_szGrp[TLK_CGROUPS]; // sentence group names - float m_useTime; // Don't allow +USE until this time - int m_iszUse; // Custom +USE sentence group (follow) - int m_iszUnUse; // Custom +USE sentence group (stop following) - - float m_flLastSaidSmelled;// last time we talked about something that stinks - float m_flStopTalkTime;// when in the future that I'll be done saying this sentence. - - EHANDLE m_hTalkTarget; // who to look at while talking - CUSTOM_SCHEDULES; -}; - - -// Clients can push talkmonsters out of their way -#define bits_COND_CLIENT_PUSH ( bits_COND_SPECIAL1 ) -// Don't see a client right now. -#define bits_COND_CLIENT_UNSEEN ( bits_COND_SPECIAL2 ) - - -#endif //TALKMONSTER_H diff --git a/sdk/dlls/teamplay_gamerules.cpp b/sdk/dlls/teamplay_gamerules.cpp deleted file mode 100644 index 8443fea..0000000 --- a/sdk/dlls/teamplay_gamerules.cpp +++ /dev/null @@ -1,627 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.cpp -// -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" -#include "game.h" - -static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; -static int team_scores[MAX_TEAMS]; -static int num_teams = 0; - -extern DLL_GLOBAL BOOL g_fGameOver; - -CHalfLifeTeamplay :: CHalfLifeTeamplay() -{ - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - - memset( team_names, 0, sizeof(team_names) ); - memset( team_scores, 0, sizeof(team_scores) ); - num_teams = 0; - - // Copy over the team from the server config - m_szTeamList[0] = 0; - - // Cache this because the team code doesn't want to deal with changing this in the middle of a game - strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH ); - - edict_t *pWorld = INDEXENT(0); - if ( pWorld && pWorld->v.team ) - { - if ( teamoverride.value ) - { - const char *pTeamList = STRING(pWorld->v.team); - if ( pTeamList && strlen(pTeamList) ) - { - strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); - } - } - } - // Has the server set teams - if ( strlen( m_szTeamList ) ) - m_teamLimit = TRUE; - else - m_teamLimit = FALSE; - - RecountTeams(); -} - -extern cvar_t timeleft, fragsleft; - -#include "voice_gamemgr.h" -extern CVoiceGameMgr g_VoiceGameMgr; - -void CHalfLifeTeamplay :: Think ( void ) -{ - ///// Check game rules ///// - static int last_frags; - static int last_time; - - int frags_remaining = 0; - int time_remaining = 0; - - g_VoiceGameMgr.Update(gpGlobals->frametime); - - if ( g_fGameOver ) // someone else quit the game already - { - CHalfLifeMultiplay::Think(); - return; - } - - float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60; - - time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); - - if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) - { - GoToIntermission(); - return; - } - - float flFragLimit = fraglimit.value; - if ( flFragLimit ) - { - int bestfrags = 9999; - int remain; - - // check if any team is over the frag limit - for ( int i = 0; i < num_teams; i++ ) - { - if ( team_scores[i] >= flFragLimit ) - { - GoToIntermission(); - return; - } - - remain = static_cast(flFragLimit - team_scores[i]); - if ( remain < bestfrags ) - { - bestfrags = remain; - } - } - frags_remaining = bestfrags; - } - - // Updates when frags change - if ( frags_remaining != last_frags ) - { - g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); - } - - // Updates once per second - if ( timeleft.value != last_time ) - { - g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); - } - - last_frags = frags_remaining; - last_time = time_remaining; -} - -//========================================================= -// ClientCommand -// the user has typed a command which is unrecognized by everything else; -// this check to see if the gamerules knows anything about the command -//========================================================= -BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) -{ - if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) - return TRUE; - - if ( FStrEq( pcmd, "menuselect" ) ) - { - if ( CMD_ARGC() < 2 ) - return TRUE; - - // select the item from the current menu - - return TRUE; - } - - return FALSE; -} - -extern int gmsgGameMode; -extern int gmsgSayText; -extern int gmsgTeamInfo; -extern int gmsgTeamNames; -extern int gmsgScoreInfo; - -void CHalfLifeTeamplay :: UpdateGameMode( CBasePlayer *pPlayer ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() ); - WRITE_BYTE( 1 ); // game mode teamplay - MESSAGE_END(); -} - - -const char *CHalfLifeTeamplay::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) -{ - // copy out the team name from the model - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - strncpy( pPlayer->m_szTeamName, mdls, TEAM_NAME_LENGTH ); - - RecountTeams(); - - // update the current player of the team he is joining - if ( pPlayer->m_szTeamName[0] == '\0' || !IsValidTeam( pPlayer->m_szTeamName ) || defaultteam.value ) - { - const char *pTeamName = NULL; - - if ( defaultteam.value ) - { - pTeamName = team_names[0]; - } - else - { - pTeamName = TeamWithFewestPlayers(); - } - strncpy( pPlayer->m_szTeamName, pTeamName, TEAM_NAME_LENGTH ); - } - - return pPlayer->m_szTeamName; -} - - -//========================================================= -// InitHUD -//========================================================= -void CHalfLifeTeamplay::InitHUD( CBasePlayer *pPlayer ) -{ - int i; - - SetDefaultPlayerTeam( pPlayer ); - CHalfLifeMultiplay::InitHUD( pPlayer ); - - // Send down the team names - MESSAGE_BEGIN( MSG_ONE, gmsgTeamNames, NULL, pPlayer->edict() ); - WRITE_BYTE( num_teams ); - for ( i = 0; i < num_teams; i++ ) - { - WRITE_STRING( team_names[ i ] ); - } - MESSAGE_END(); - - RecountTeams(); - - char *mdls = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model" ); - // update the current player of the team he is joining - char text[1024]; - if ( !strcmp( mdls, pPlayer->m_szTeamName ) ) - { - sprintf( text, "* you are on team \'%s\'\n", pPlayer->m_szTeamName ); - } - else - { - sprintf( text, "* assigned to team %s\n", pPlayer->m_szTeamName ); - } - - ChangePlayerTeam( pPlayer, pPlayer->m_szTeamName, FALSE, FALSE ); - UTIL_SayText( text, pPlayer ); - RecountTeams(); - // update this player with all the other players team info - // loop through all active players and send their team info to the new client - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if ( plr && IsValidTeam( plr->TeamID() ) ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgTeamInfo, NULL, pPlayer->edict() ); - WRITE_BYTE( plr->entindex() ); - WRITE_STRING( plr->TeamID() ); - MESSAGE_END(); - } - } -} - - -void CHalfLifeTeamplay::ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) -{ - int damageFlags = DMG_GENERIC; - int clientIndex = pPlayer->entindex(); - - if ( !bGib ) - { - damageFlags |= DMG_NEVERGIB; - } - else - { - damageFlags |= DMG_ALWAYSGIB; - } - - if ( bKill ) - { - // kill the player, remove a death, and let them start on the new team - m_DisableDeathMessages = TRUE; - m_DisableDeathPenalty = TRUE; - - entvars_t *pevWorld = VARS( INDEXENT(0) ); - pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); - - m_DisableDeathMessages = FALSE; - m_DisableDeathPenalty = FALSE; - } - - // copy out the team name from the model - strncpy( pPlayer->m_szTeamName, pTeamName, TEAM_NAME_LENGTH ); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); - - // notify everyone's HUD of the team change - MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); - WRITE_BYTE( clientIndex ); - WRITE_STRING( pPlayer->m_szTeamName ); - MESSAGE_END(); - - MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); - WRITE_BYTE( clientIndex ); - WRITE_SHORT( static_cast(pPlayer->pev->frags) ); - WRITE_SHORT( pPlayer->m_iDeaths ); - WRITE_SHORT( 0 ); - WRITE_SHORT( g_pGameRules->GetTeamIndex( pPlayer->m_szTeamName ) + 1 ); - MESSAGE_END(); -} - - -//========================================================= -// ClientUserInfoChanged -//========================================================= -void CHalfLifeTeamplay::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) -{ - char text[1024]; - - // prevent skin/color/model changes - char *mdls = g_engfuncs.pfnInfoKeyValue( infobuffer, "model" ); - - if ( !stricmp( mdls, pPlayer->m_szTeamName ) ) - return; - - if ( defaultteam.value ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "team", pPlayer->m_szTeamName ); - sprintf( text, "* Not allowed to change teams in this game!\n" ); - UTIL_SayText( text, pPlayer ); - return; - } - - if ( defaultteam.value || !IsValidTeam( mdls ) ) - { - int clientIndex = pPlayer->entindex(); - - g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", pPlayer->m_szTeamName ); - sprintf( text, "* Can't change team to \'%s\'\n", mdls ); - UTIL_SayText( text, pPlayer ); - sprintf( text, "* Server limits teams to \'%s\'\n", m_szTeamList ); - UTIL_SayText( text, pPlayer ); - return; - } - // notify everyone of the team change - sprintf( text, "* %s has changed to team \'%s\'\n", STRING(pPlayer->pev->netname), mdls ); - UTIL_SayTextAll( text, pPlayer ); - - UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n", - STRING(pPlayer->pev->netname), - GETPLAYERUSERID( pPlayer->edict() ), - GETPLAYERAUTHID( pPlayer->edict() ), - pPlayer->m_szTeamName, - mdls ); - - ChangePlayerTeam( pPlayer, mdls, TRUE, TRUE ); - // recound stuff - RecountTeams( TRUE ); -} - -extern int gmsgDeathMsg; - -//========================================================= -// Deathnotice. -//========================================================= -void CHalfLifeTeamplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) -{ - if ( m_DisableDeathMessages ) - return; - - if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) - { - CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); - - if ( pk ) - { - if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) - { - MESSAGE_BEGIN( MSG_ALL, gmsgDeathMsg ); - WRITE_BYTE( ENTINDEX(ENT(pKiller)) ); // the killer - WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim - WRITE_STRING( "teammate" ); // flag this as a teammate kill - MESSAGE_END(); - return; - } - } - } - - CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); -} - -//========================================================= -//========================================================= -void CHalfLifeTeamplay :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) -{ - if ( !m_DisableDeathPenalty ) - { - CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); - RecountTeams(); - } -} - - -//========================================================= -// IsTeamplay -//========================================================= -BOOL CHalfLifeTeamplay::IsTeamplay( void ) -{ - return TRUE; -} - -BOOL CHalfLifeTeamplay::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) -{ - if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) - { - // my teammate hit me. - if ( (friendlyfire.value == 0) && (pAttacker != pPlayer) ) - { - // friendly fire is off, and this hit came from someone other than myself, then don't get hurt - return FALSE; - } - } - - return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) -{ - // half life multiplay has a simple concept of Player Relationships. - // you are either on another player's team, or you are not. - if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) - return GR_NOTTEAMMATE; - - if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) - { - return GR_TEAMMATE; - } - - return GR_NOTTEAMMATE; -} - -//========================================================= -//========================================================= -BOOL CHalfLifeTeamplay::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) -{ - // always autoaim, unless target is a teammate - CBaseEntity *pTgt = CBaseEntity::Instance( target ); - if ( pTgt && pTgt->IsPlayer() ) - { - if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) - return FALSE; // don't autoaim at teammates - } - - return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); -} - -//========================================================= -//========================================================= -int CHalfLifeTeamplay::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) -{ - if ( !pKilled ) - return 0; - - if ( !pAttacker ) - return 1; - - if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) - return -1; - - return 1; -} - -//========================================================= -//========================================================= -const char *CHalfLifeTeamplay::GetTeamID( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL || pEntity->pev == NULL ) - return ""; - - // return their team name - return pEntity->TeamID(); -} - - -int CHalfLifeTeamplay::GetTeamIndex( const char *pTeamName ) -{ - if ( pTeamName && *pTeamName != 0 ) - { - // try to find existing team - for ( int tm = 0; tm < num_teams; tm++ ) - { - if ( !stricmp( team_names[tm], pTeamName ) ) - return tm; - } - } - - return -1; // No match -} - - -const char *CHalfLifeTeamplay::GetIndexedTeamName( int teamIndex ) -{ - if ( teamIndex < 0 || teamIndex >= num_teams ) - return ""; - - return team_names[ teamIndex ]; -} - - -BOOL CHalfLifeTeamplay::IsValidTeam( const char *pTeamName ) -{ - if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set - return TRUE; - - return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; -} - -const char *CHalfLifeTeamplay::TeamWithFewestPlayers( void ) -{ - int i; - int minPlayers = MAX_TEAMS; - int teamCount[ MAX_TEAMS ]; - char *pTeamName = NULL; - - memset( teamCount, 0, MAX_TEAMS * sizeof(int) ); - - // loop through all clients, count number of players on each team - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - int team = GetTeamIndex( plr->TeamID() ); - if ( team >= 0 ) - teamCount[team] ++; - } - } - - // Find team with least players - for ( i = 0; i < num_teams; i++ ) - { - if ( teamCount[i] < minPlayers ) - { - minPlayers = teamCount[i]; - pTeamName = team_names[i]; - } - } - - return pTeamName; -} - - -//========================================================= -//========================================================= -void CHalfLifeTeamplay::RecountTeams( bool bResendInfo ) -{ - char *pName; - char teamlist[TEAMPLAY_TEAMLISTLENGTH]; - - // loop through all teams, recounting everything - num_teams = 0; - - // Copy all of the teams from the teamlist - // make a copy because strtok is destructive - strcpy( teamlist, m_szTeamList ); - pName = teamlist; - pName = strtok( pName, ";" ); - while ( pName != NULL && *pName ) - { - if ( GetTeamIndex( pName ) < 0 ) - { - strcpy( team_names[num_teams], pName ); - num_teams++; - } - pName = strtok( NULL, ";" ); - } - - if ( num_teams < 2 ) - { - num_teams = 0; - m_teamLimit = FALSE; - } - - // Sanity check - memset( team_scores, 0, sizeof(team_scores) ); - - // loop through all clients - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *plr = UTIL_PlayerByIndex( i ); - - if ( plr ) - { - const char *pTeamName = plr->TeamID(); - // try add to existing team - int tm = GetTeamIndex( pTeamName ); - - if ( tm < 0 ) // no team match found - { - if ( !m_teamLimit ) - { - // add to new team - tm = num_teams; - num_teams++; - team_scores[tm] = 0; - strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); - } - } - - if ( tm >= 0 ) - { - team_scores[tm] += static_cast(plr->pev->frags); - } - - if ( bResendInfo ) //Someone's info changed, let's send the team info again. - { - if ( plr && IsValidTeam( plr->TeamID() ) ) - { - MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo, NULL ); - WRITE_BYTE( plr->entindex() ); - WRITE_STRING( plr->TeamID() ); - MESSAGE_END(); - } - } - } - } -} diff --git a/sdk/dlls/teamplay_gamerules.h b/sdk/dlls/teamplay_gamerules.h deleted file mode 100644 index 5d4246b..0000000 --- a/sdk/dlls/teamplay_gamerules.h +++ /dev/null @@ -1,57 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// teamplay_gamerules.h -// - -#define MAX_TEAMNAME_LENGTH 16 -#define MAX_TEAMS 32 - -#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH - -class CHalfLifeTeamplay : public CHalfLifeMultiplay -{ -public: - CHalfLifeTeamplay(); - - virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); - virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); - virtual BOOL IsTeamplay( void ); - virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); - virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); - virtual const char *GetTeamID( CBaseEntity *pEntity ); - virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); - virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); - virtual void InitHUD( CBasePlayer *pl ); - virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); - virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser - virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode - virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); - virtual void Think ( void ); - virtual int GetTeamIndex( const char *pTeamName ); - virtual const char *GetIndexedTeamName( int teamIndex ); - virtual BOOL IsValidTeam( const char *pTeamName ); - const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); - virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); - -private: - void RecountTeams( bool bResendInfo = FALSE ); - const char *TeamWithFewestPlayers( void ); - - BOOL m_DisableDeathMessages; - BOOL m_DisableDeathPenalty; - BOOL m_teamLimit; // This means the server set only some teams as valid - char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; -}; diff --git a/sdk/dlls/tempmonster.cpp b/sdk/dlls/tempmonster.cpp deleted file mode 100644 index 793ca90..0000000 --- a/sdk/dlls/tempmonster.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// monster template -//========================================================= -#if 0 - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -class CMyMonster : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); -}; -LINK_ENTITY_TO_CLASS( my_monster, CMyMonster ); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CMyMonster :: Classify ( void ) -{ - return CLASS_MY_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CMyMonster :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - default: - ys = 90; - } - - pev->yaw_speed = ys; -} - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CMyMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case 0: - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CMyMonster :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/mymodel.mdl"); - UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = 8; - pev->view_ofs = Vector ( 0, 0, 0 );// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CMyMonster :: Precache() -{ - PRECACHE_SOUND("mysound.wav"); - - PRECACHE_MODEL("models/mymodel.mdl"); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= -#endif diff --git a/sdk/dlls/tentacle.cpp b/sdk/dlls/tentacle.cpp deleted file mode 100644 index ed4b0f9..0000000 --- a/sdk/dlls/tentacle.cpp +++ /dev/null @@ -1,1046 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - -/* - - h_tentacle.cpp - silo of death tentacle monster (half life) - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "soundent.h" - - -#define ACT_T_IDLE 1010 -#define ACT_T_TAP 1020 -#define ACT_T_STRIKE 1030 -#define ACT_T_REARIDLE 1040 - -class CTentacle : public CBaseMonster -{ -public: - CTentacle( void ); - - void Spawn( ); - void Precache( ); - void KeyValue( KeyValueData *pkvd ); - - int Save( CSave &save ); - int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - // Don't allow the tentacle to go across transitions!!! - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - void SetObjectCollisionBox( void ) - { - pev->absmin = pev->origin + Vector(-400, -400, 0); - pev->absmax = pev->origin + Vector(400, 400, 850); - } - - void EXPORT Cycle( void ); - void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT Start( void ); - void EXPORT DieThink( void ); - - void EXPORT Test( void ); - - void EXPORT HitTouch( CBaseEntity *pOther ); - - float HearingSensitivity( void ) { return 2.0; }; - - int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Killed( entvars_t *pevAttacker, int iGib ); - - MONSTERSTATE GetIdealState ( void ) { return MONSTERSTATE_IDLE; }; - int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; - - int Classify( void ); - - int Level( float dz ); - int MyLevel( void ); - float MyHeight( void ); - - float m_flInitialYaw; - int m_iGoalAnim; - int m_iLevel; - int m_iDir; - float m_flFramerateAdj; - float m_flSoundYaw; - int m_iSoundLevel; - float m_flSoundTime; - float m_flSoundRadius; - int m_iHitDmg; - float m_flHitTime; - - float m_flTapRadius; - - float m_flNextSong; - static int g_fFlySound; - static int g_fSquirmSound; - - float m_flMaxYaw; - int m_iTapSound; - - Vector m_vecPrevSound; - float m_flPrevSoundTime; - - static const char *pHitSilo[]; - static const char *pHitDirt[]; - static const char *pHitWater[]; -}; - - - -int CTentacle :: g_fFlySound; -int CTentacle :: g_fSquirmSound; - -LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); - -// stike sounds -#define TE_NONE -1 -#define TE_SILO 0 -#define TE_DIRT 1 -#define TE_WATER 2 - -const char *CTentacle::pHitSilo[] = -{ - "tentacle/te_strike1.wav", - "tentacle/te_strike2.wav", -}; - -const char *CTentacle::pHitDirt[] = -{ - "player/pl_dirt1.wav", - "player/pl_dirt2.wav", - "player/pl_dirt3.wav", - "player/pl_dirt4.wav", -}; - -const char *CTentacle::pHitWater[] = -{ - "player/pl_slosh1.wav", - "player/pl_slosh2.wav", - "player/pl_slosh3.wav", - "player/pl_slosh4.wav", -}; - - -TYPEDESCRIPTION CTentacle::m_SaveData[] = -{ - DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_iDir, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flFramerateAdj, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flSoundYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iSoundLevel, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flSoundTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flSoundRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_iHitDmg, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flHitTime, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_flTapRadius, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_flNextSong, FIELD_TIME ), - DEFINE_FIELD( CTentacle, m_iTapSound, FIELD_INTEGER ), - DEFINE_FIELD( CTentacle, m_flMaxYaw, FIELD_FLOAT ), - DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ); - - -// animation sequence aliases -typedef enum -{ - TENTACLE_ANIM_Pit_Idle, - - TENTACLE_ANIM_rise_to_Temp1, - TENTACLE_ANIM_Temp1_to_Floor, - TENTACLE_ANIM_Floor_Idle, - TENTACLE_ANIM_Floor_Fidget_Pissed, - TENTACLE_ANIM_Floor_Fidget_SmallRise, - TENTACLE_ANIM_Floor_Fidget_Wave, - TENTACLE_ANIM_Floor_Strike, - TENTACLE_ANIM_Floor_Tap, - TENTACLE_ANIM_Floor_Rotate, - TENTACLE_ANIM_Floor_Rear, - TENTACLE_ANIM_Floor_Rear_Idle, - TENTACLE_ANIM_Floor_to_Lev1, - - TENTACLE_ANIM_Lev1_Idle, - TENTACLE_ANIM_Lev1_Fidget_Claw, - TENTACLE_ANIM_Lev1_Fidget_Shake, - TENTACLE_ANIM_Lev1_Fidget_Snap, - TENTACLE_ANIM_Lev1_Strike, - TENTACLE_ANIM_Lev1_Tap, - TENTACLE_ANIM_Lev1_Rotate, - TENTACLE_ANIM_Lev1_Rear, - TENTACLE_ANIM_Lev1_Rear_Idle, - TENTACLE_ANIM_Lev1_to_Lev2, - - TENTACLE_ANIM_Lev2_Idle, - TENTACLE_ANIM_Lev2_Fidget_Shake, - TENTACLE_ANIM_Lev2_Fidget_Swing, - TENTACLE_ANIM_Lev2_Fidget_Tut, - TENTACLE_ANIM_Lev2_Strike, - TENTACLE_ANIM_Lev2_Tap, - TENTACLE_ANIM_Lev2_Rotate, - TENTACLE_ANIM_Lev2_Rear, - TENTACLE_ANIM_Lev2_Rear_Idle, - TENTACLE_ANIM_Lev2_to_Lev3, - - TENTACLE_ANIM_Lev3_Idle, - TENTACLE_ANIM_Lev3_Fidget_Shake, - TENTACLE_ANIM_Lev3_Fidget_Side, - TENTACLE_ANIM_Lev3_Fidget_Swipe, - TENTACLE_ANIM_Lev3_Strike, - TENTACLE_ANIM_Lev3_Tap, - TENTACLE_ANIM_Lev3_Rotate, - TENTACLE_ANIM_Lev3_Rear, - TENTACLE_ANIM_Lev3_Rear_Idle, - - TENTACLE_ANIM_Lev1_Door_reach, - - TENTACLE_ANIM_Lev3_to_Engine, - TENTACLE_ANIM_Engine_Idle, - TENTACLE_ANIM_Engine_Sway, - TENTACLE_ANIM_Engine_Swat, - TENTACLE_ANIM_Engine_Bob, - TENTACLE_ANIM_Engine_Death1, - TENTACLE_ANIM_Engine_Death2, - TENTACLE_ANIM_Engine_Death3, - - TENTACLE_ANIM_none -} TENTACLE_ANIM; - - - - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CTentacle :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -// -// Tentacle Spawn -// -void CTentacle :: Spawn( ) -{ - Precache( ); - - pev->solid = SOLID_BBOX; - pev->movetype = MOVETYPE_FLY; - pev->effects = 0; - pev->health = 75; - pev->sequence = 0; - - SET_MODEL(ENT(pev), "models/tentacle2.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); - - pev->takedamage = DAMAGE_AIM; - pev->flags |= FL_MONSTER; - - m_bloodColor = BLOOD_COLOR_GREEN; - - SetThink( &CTentacle::Start ); - SetTouch( &CTentacle::HitTouch ); - SetUse( &CTentacle::CommandUse ); - - pev->nextthink = gpGlobals->time + 0.2; - - ResetSequenceInfo( ); - m_iDir = 1; - - pev->yaw_speed = 18; - m_flInitialYaw = pev->angles.y; - pev->ideal_yaw = m_flInitialYaw; - - g_fFlySound = FALSE; - g_fSquirmSound = FALSE; - - m_iHitDmg = 20; - - if (m_flMaxYaw <= 0) - m_flMaxYaw = 65; - - m_MonsterState = MONSTERSTATE_IDLE; - - // SetThink( Test ); - UTIL_SetOrigin( pev, pev->origin ); -} - -void CTentacle :: Precache( ) -{ - PRECACHE_MODEL("models/tentacle2.mdl"); - - PRECACHE_SOUND("ambience/flies.wav"); - PRECACHE_SOUND("ambience/squirm2.wav"); - - PRECACHE_SOUND("tentacle/te_alert1.wav"); - PRECACHE_SOUND("tentacle/te_alert2.wav"); - PRECACHE_SOUND("tentacle/te_flies1.wav"); - PRECACHE_SOUND("tentacle/te_move1.wav"); - PRECACHE_SOUND("tentacle/te_move2.wav"); - PRECACHE_SOUND("tentacle/te_roar1.wav"); - PRECACHE_SOUND("tentacle/te_roar2.wav"); - PRECACHE_SOUND("tentacle/te_search1.wav"); - PRECACHE_SOUND("tentacle/te_search2.wav"); - PRECACHE_SOUND("tentacle/te_sing1.wav"); - PRECACHE_SOUND("tentacle/te_sing2.wav"); - PRECACHE_SOUND("tentacle/te_squirm2.wav"); - PRECACHE_SOUND("tentacle/te_strike1.wav"); - PRECACHE_SOUND("tentacle/te_strike2.wav"); - PRECACHE_SOUND("tentacle/te_swing1.wav"); - PRECACHE_SOUND("tentacle/te_swing2.wav"); - - PRECACHE_SOUND_ARRAY( pHitSilo ); - PRECACHE_SOUND_ARRAY( pHitDirt ); - PRECACHE_SOUND_ARRAY( pHitWater ); -} - - -CTentacle::CTentacle( ) -{ - m_flMaxYaw = 65; - m_iTapSound = 0; -} - -void CTentacle::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "sweeparc")) - { - m_flMaxYaw = atof(pkvd->szValue) / 2.0; - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "sound")) - { - m_iTapSound = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else - CBaseMonster::KeyValue( pkvd ); -} - - - -int CTentacle :: Level( float dz ) -{ - if (dz < 216) - return 0; - if (dz < 408) - return 1; - if (dz < 600) - return 2; - return 3; -} - - -float CTentacle :: MyHeight( ) -{ - switch ( MyLevel( ) ) - { - case 1: - return 256; - case 2: - return 448; - case 3: - return 640; - } - return 0; -} - - -int CTentacle :: MyLevel( ) -{ - switch( pev->sequence ) - { - case TENTACLE_ANIM_Pit_Idle: - return -1; - - case TENTACLE_ANIM_rise_to_Temp1: - case TENTACLE_ANIM_Temp1_to_Floor: - case TENTACLE_ANIM_Floor_to_Lev1: - return 0; - - case TENTACLE_ANIM_Floor_Idle: - case TENTACLE_ANIM_Floor_Fidget_Pissed: - case TENTACLE_ANIM_Floor_Fidget_SmallRise: - case TENTACLE_ANIM_Floor_Fidget_Wave: - case TENTACLE_ANIM_Floor_Strike: - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Floor_Rotate: - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - return 0; - - case TENTACLE_ANIM_Lev1_Idle: - case TENTACLE_ANIM_Lev1_Fidget_Claw: - case TENTACLE_ANIM_Lev1_Fidget_Shake: - case TENTACLE_ANIM_Lev1_Fidget_Snap: - case TENTACLE_ANIM_Lev1_Strike: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev1_Rotate: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - return 1; - - case TENTACLE_ANIM_Lev1_to_Lev2: - return 1; - - case TENTACLE_ANIM_Lev2_Idle: - case TENTACLE_ANIM_Lev2_Fidget_Shake: - case TENTACLE_ANIM_Lev2_Fidget_Swing: - case TENTACLE_ANIM_Lev2_Fidget_Tut: - case TENTACLE_ANIM_Lev2_Strike: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev2_Rotate: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - return 2; - - case TENTACLE_ANIM_Lev2_to_Lev3: - return 2; - - case TENTACLE_ANIM_Lev3_Idle: - case TENTACLE_ANIM_Lev3_Fidget_Shake: - case TENTACLE_ANIM_Lev3_Fidget_Side: - case TENTACLE_ANIM_Lev3_Fidget_Swipe: - case TENTACLE_ANIM_Lev3_Strike: - case TENTACLE_ANIM_Lev3_Tap: - case TENTACLE_ANIM_Lev3_Rotate: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - return 3; - - case TENTACLE_ANIM_Lev1_Door_reach: - return -1; - } - return -1; -} - - -void CTentacle :: Test( void ) -{ - pev->sequence = TENTACLE_ANIM_Floor_Strike; - pev->framerate = 0; - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; -} - - - -// -// TentacleThink -// -void CTentacle :: Cycle( void ) -{ - // ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); - pev->nextthink = gpGlobals-> time + 0.1; - - // ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); - - if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT) - { - pev->angles.y = m_flInitialYaw; - pev->ideal_yaw = m_flInitialYaw; - ClearConditions( IgnoreConditions() ); - MonsterThink( ); - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; - } - - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ChangeYaw( pev->yaw_speed ); - - CSound *pSound; - - Listen( ); - - // Listen will set this if there's something in my sound list - if ( HasConditions( bits_COND_HEAR_SOUND ) ) - pSound = PBestSound(); - else - pSound = NULL; - - if ( pSound ) - { - Vector vecDir; - if (gpGlobals->time - m_flPrevSoundTime < 0.5) - { - float dt = gpGlobals->time - m_flPrevSoundTime; - vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin; - } - else - { - vecDir = pSound->m_vecOrigin - pev->origin; - } - m_flPrevSoundTime = gpGlobals->time; - m_vecPrevSound = pSound->m_vecOrigin; - - m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; - m_iSoundLevel = Level( vecDir.z ); - - if (m_flSoundYaw < -180) - m_flSoundYaw += 360; - if (m_flSoundYaw > 180) - m_flSoundYaw -= 360; - - // ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); -#if 0 - if (m_flSoundTime < gpGlobals->time) - { - // play "I hear new something" sound - const char *sound; - - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_alert1.wav"; break; - case 1: sound = "tentacle/te_alert2.wav"; break; - } - - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - } -#endif - m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); - } - - // clip ideal_yaw - float dy = m_flSoundYaw; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - if (dy < 0 && dy > -m_flMaxYaw) - dy = -m_flMaxYaw; - if (dy > 0 && dy < m_flMaxYaw) - dy = m_flMaxYaw; - break; - default: - if (dy < -m_flMaxYaw) - dy = -m_flMaxYaw; - if (dy > m_flMaxYaw) - dy = m_flMaxYaw; - } - pev->ideal_yaw = m_flInitialYaw + dy; - - if (m_fSequenceFinished) - { - // ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); - if (pev->health <= 1) - { - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - if (pev->sequence == TENTACLE_ANIM_Pit_Idle) - { - pev->health = 75; - } - } - else if ( m_flSoundTime > gpGlobals->time ) - { - if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) - { - // strike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - else - { - // go into rear idle - m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); - } - } - else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) - { - // stay in pit until hear noise - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - } - else if (pev->sequence == m_iGoalAnim) - { - if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) - { - if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) - { - // continue stike - m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); - } - else - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); - } - } - else if (MyLevel( ) < 0) - { - m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); - } - else - { - if (m_flNextSong < gpGlobals->time) - { - // play "I hear new something" sound - const char *sound = NULL; - - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_sing1.wav"; break; - case 1: sound = "tentacle/te_sing2.wav"; break; - } - - EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM); - - m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); - } - - if (RANDOM_LONG(0,15) == 0) - { - // idle on new level - m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); - } - else if (RANDOM_LONG(0,3) == 0) - { - // tap - m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); - } - else - { - // idle - m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); - } - } - if (m_flSoundYaw < 0) - m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); - else - m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); - } - - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - - if (m_iDir > 0) - { - pev->frame = 0; - } - else - { - m_iDir = -1; // just to safe - pev->frame = 255; - } - ResetSequenceInfo( ); - - m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); - pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; - - switch( pev->sequence) - { - case TENTACLE_ANIM_Floor_Tap: - case TENTACLE_ANIM_Lev1_Tap: - case TENTACLE_ANIM_Lev2_Tap: - case TENTACLE_ANIM_Lev3_Tap: - { - Vector vecSrc; - UTIL_MakeVectors( pev->angles ); - - TraceResult tr1, tr2; - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); - - vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8); - UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); - - // ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); - - m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); - } - break; - default: - m_flTapRadius = 336; // 400 - 64 - break; - } - pev->view_ofs.z = MyHeight( ); - // ALERT( at_console, "seq %d\n", pev->sequence ); - } - - if (m_flPrevSoundTime + 2.0 > gpGlobals->time) - { - // 1.5 normal speed if hears sounds - pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; - } - else if (m_flPrevSoundTime + 5.0 > gpGlobals->time) - { - // slowdown to normal - pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj; - } -} - - - -void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); - switch( useType ) - { - case USE_OFF: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; - break; - case USE_ON: - if (pActivator) - { - // ALERT( at_console, "insert sound\n"); - CSoundEnt::InsertSound ( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); - } - break; - case USE_SET: - break; - case USE_TOGGLE: - pev->takedamage = DAMAGE_NO; - SetThink( &CTentacle::DieThink ); - m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; - break; - } - -} - - - -void CTentacle :: DieThink( void ) -{ - pev->nextthink = gpGlobals-> time + 0.1; - - DispatchAnimEvents( ); - StudioFrameAdvance( ); - - ChangeYaw( 24 ); - - if (m_fSequenceFinished) - { - if (pev->sequence == m_iGoalAnim) - { - switch( m_iGoalAnim ) - { - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 ); - break; - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - UTIL_Remove( this ); - return; - } - } - - // ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim ); - pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); - // ALERT( at_console, "%d\n", pev->sequence ); - - if (m_iDir > 0) - { - pev->frame = 0; - } - else - { - pev->frame = 255; - } - ResetSequenceInfo( ); - - float dy; - switch( pev->sequence ) - { - case TENTACLE_ANIM_Floor_Rear: - case TENTACLE_ANIM_Floor_Rear_Idle: - case TENTACLE_ANIM_Lev1_Rear: - case TENTACLE_ANIM_Lev1_Rear_Idle: - case TENTACLE_ANIM_Lev2_Rear: - case TENTACLE_ANIM_Lev2_Rear_Idle: - case TENTACLE_ANIM_Lev3_Rear: - case TENTACLE_ANIM_Lev3_Rear_Idle: - case TENTACLE_ANIM_Engine_Idle: - case TENTACLE_ANIM_Engine_Sway: - case TENTACLE_ANIM_Engine_Swat: - case TENTACLE_ANIM_Engine_Bob: - case TENTACLE_ANIM_Engine_Death1: - case TENTACLE_ANIM_Engine_Death2: - case TENTACLE_ANIM_Engine_Death3: - pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 ); - dy = 180; - break; - default: - pev->framerate = 1.5; - dy = 0; - break; - } - pev->ideal_yaw = m_flInitialYaw + dy; - } -} - - -void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - const char *sound = NULL; - - switch( pEvent->event ) - { - case 1: // bang - { - Vector vecSrc, vecAngles; - GetAttachment( 0, vecSrc, vecAngles ); - - // Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (3.14192653 / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); - - // vecSrc.z += MyHeight( ); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, ATTN_NORM, 0, 100); - break; - case TE_WATER: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100); - break; - } - gpGlobals->force_retouch++; - } - break; - - case 3: // start killing swing - m_iHitDmg = 200; - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing1.wav", 1.0, ATTN_NORM, 0, 100); - break; - - case 4: // end killing swing - m_iHitDmg = 25; - break; - - case 5: // just "whoosh" sound - // UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing2.wav", 1.0, ATTN_NORM, 0, 100); - break; - - case 2: // tap scrape - case 6: // light tap - { - Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (M_PI / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); - - vecSrc.z += MyHeight( ); - - float flVol = RANDOM_FLOAT( 0.3, 0.5 ); - - switch( m_iTapSound ) - { - case TE_SILO: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, ATTN_NORM, 0, 100); - break; - case TE_NONE: - break; - case TE_DIRT: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, ATTN_NORM, 0, 100); - break; - case TE_WATER: - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, ATTN_NORM, 0, 100); - break; - } - } - break; - - - case 7: // roar - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_roar1.wav"; break; - case 1: sound = "tentacle/te_roar2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - case 8: // search - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_search1.wav"; break; - case 1: sound = "tentacle/te_search2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - case 9: // swing - switch( RANDOM_LONG(0,1) ) - { - case 0: sound = "tentacle/te_move1.wav"; break; - case 1: sound = "tentacle/te_move2.wav"; break; - } - - UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - } -} - - -// -// TentacleStart -// -// void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -void CTentacle :: Start( void ) -{ - SetThink( &CTentacle::Cycle ); - - if ( !g_fFlySound ) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); - g_fFlySound = TRUE; -// pev->nextthink = gpGlobals-> time + 0.1; - } - else if ( !g_fSquirmSound ) - { - EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); - g_fSquirmSound = TRUE; - } - - pev->nextthink = gpGlobals->time + 0.1; -} - - - - -void CTentacle :: HitTouch( CBaseEntity *pOther ) -{ - TraceResult tr = UTIL_GetGlobalTrace( ); - - if (pOther->pev->modelindex == pev->modelindex) - return; - - if (m_flHitTime > gpGlobals->time) - return; - - // only look at the ones where the player hit me - if (tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex) - return; - - if (tr.iHitgroup >= 3) - { - pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); - // ALERT( at_console, "wack %3d : ", m_iHitDmg ); - } - else if (tr.iHitgroup != 0) - { - pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); - // ALERT( at_console, "tap %3d : ", 20 ); - } - else - { - return; // Huh? - } - - m_flHitTime = gpGlobals->time + 0.5; - - // ALERT( at_console, "%s : ", STRING( tr.pHit->v.classname ) ); - - // ALERT( at_console, "%.0f : %s : %d\n", pev->angles.y, STRING( pOther->pev->classname ), tr.iHitgroup ); -} - - -int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) -{ - if (flDamage > pev->health) - { - pev->health = 1; - } - else - { - pev->health -= flDamage; - } - return 1; -} - - - - -void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) -{ - m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; - return; -} - - - -class CTentacleMaw : public CBaseMonster -{ -public: - void Spawn( ); - void Precache( ); -}; - -LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ); - -// -// Tentacle Spawn -// -void CTentacleMaw :: Spawn( ) -{ - Precache( ); - SET_MODEL(ENT(pev), "models/maw.mdl"); - UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_STEP; - pev->effects = 0; - pev->health = 75; - pev->yaw_speed = 8; - pev->sequence = 0; - - pev->angles.x = 90; - // ResetSequenceInfo( ); -} - -void CTentacleMaw :: Precache( ) -{ - PRECACHE_MODEL("models/maw.mdl"); -} - -#endif diff --git a/sdk/dlls/trains.h b/sdk/dlls/trains.h deleted file mode 100644 index 87aec76..0000000 --- a/sdk/dlls/trains.h +++ /dev/null @@ -1,127 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef TRAINS_H -#define TRAINS_H - -// Tracktrain spawn flags -#define SF_TRACKTRAIN_NOPITCH 0x0001 -#define SF_TRACKTRAIN_NOCONTROL 0x0002 -#define SF_TRACKTRAIN_FORWARDONLY 0x0004 -#define SF_TRACKTRAIN_PASSABLE 0x0008 - -// Spawnflag for CPathTrack -#define SF_PATH_DISABLED 0x00000001 -#define SF_PATH_FIREONCE 0x00000002 -#define SF_PATH_ALTREVERSE 0x00000004 -#define SF_PATH_DISABLE_TRAIN 0x00000008 -#define SF_PATH_ALTERNATE 0x00008000 - -// Spawnflags of CPathCorner -#define SF_CORNER_WAITFORTRIG 0x001 -#define SF_CORNER_TELEPORT 0x002 -#define SF_CORNER_FIREONCE 0x004 - -//#define PATH_SPARKLE_DEBUG 1 // This makes a particle effect around path_track entities for debugging -class CPathTrack : public CPointEntity -{ -public: - void Spawn( void ); - void Activate( void ); - void KeyValue( KeyValueData* pkvd); - - void SetPrevious( CPathTrack *pprevious ); - void Link( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - CPathTrack *ValidPath( CPathTrack *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise - void Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ); - - static CPathTrack *Instance( edict_t *pent ); - - CPathTrack *LookAhead( Vector *origin, float dist, int move ); - CPathTrack *Nearest( Vector origin ); - - CPathTrack *GetNext( void ); - CPathTrack *GetPrevious( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; -#if PATH_SPARKLE_DEBUG - void EXPORT Sparkle(void); -#endif - - float m_length; - string_t m_altName; - CPathTrack *m_pnext; - CPathTrack *m_pprevious; - CPathTrack *m_paltpath; -}; - - -class CFuncTrackTrain : public CBaseEntity -{ -public: - void Spawn( void ); - void Precache( void ); - - void Blocked( CBaseEntity *pOther ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void KeyValue( KeyValueData* pkvd ); - - void EXPORT Next( void ); - void EXPORT Find( void ); - void EXPORT NearestPath( void ); - void EXPORT DeadEnd( void ); - - void NextThink( float thinkTime, BOOL alwaysThink ); - - void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(pev->origin); } - void SetControls( entvars_t *pevControls ); - BOOL OnControls( entvars_t *pev ); - - void StopSound ( void ); - void UpdateSound ( void ); - - static CFuncTrackTrain *Instance( edict_t *pent ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DIRECTIONAL_USE; } - - virtual void OverrideReset( void ); - - CPathTrack *m_ppath; - float m_length; - float m_height; - float m_speed; - float m_dir; - float m_startSpeed; - Vector m_controlMins; - Vector m_controlMaxs; - int m_soundPlaying; - int m_sounds; - float m_flVolume; - float m_flBank; - float m_oldSpeed; - -private: - unsigned short m_usAdjustPitch; -}; - -#endif diff --git a/sdk/dlls/triggers.cpp b/sdk/dlls/triggers.cpp deleted file mode 100644 index a36a685..0000000 --- a/sdk/dlls/triggers.cpp +++ /dev/null @@ -1,2429 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== triggers.cpp ======================================================== - - spawn and use functions for editor-placed triggers - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "saverestore.h" -#include "trains.h" // trigger_camera has train functionality -#include "gamerules.h" - -#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once -#define SF_TRIGGER_HURT_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_NO_CLIENTS 8//spawnflag that makes trigger_push spawn turned OFF -#define SF_TRIGGER_HURT_CLIENTONLYFIRE 16// trigger hurt will only fire its target if it is hurting a client -#define SF_TRIGGER_HURT_CLIENTONLYTOUCH 32// only clients may touch this trigger. - -extern DLL_GLOBAL BOOL g_fGameOver; - -extern void SetMovedir(entvars_t* pev); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -class CFrictionModifier : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT ChangeFriction( CBaseEntity *pOther ); - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - static TYPEDESCRIPTION m_SaveData[]; - - float m_frictionFraction; // Sorry, couldn't resist this name :) -}; - -LINK_ENTITY_TO_CLASS( func_friction, CFrictionModifier ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CFrictionModifier::m_SaveData[] = -{ - DEFINE_FIELD( CFrictionModifier, m_frictionFraction, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CFrictionModifier,CBaseEntity); - - -// Modify an entity's friction -void CFrictionModifier :: Spawn( void ) -{ - pev->solid = SOLID_TRIGGER; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_NONE; - SetTouch( &CFrictionModifier::ChangeFriction ); -} - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: ChangeFriction( CBaseEntity *pOther ) -{ - if ( pOther->pev->movetype != MOVETYPE_BOUNCEMISSILE && pOther->pev->movetype != MOVETYPE_BOUNCE ) - pOther->pev->friction = m_frictionFraction; -} - - - -// Sets toucher's friction to m_frictionFraction (1.0 = normal friction) -void CFrictionModifier :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "modifier")) - { - m_frictionFraction = atof(pkvd->szValue) / 100.0; - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// This trigger will fire when the level spawns (or respawns if not fire once) -// It will check a global state before firing. It supports delay and killtargets - -#define SF_AUTO_FIREONCE 0x0001 - -class CAutoTrigger : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Precache( void ); - void Think( void ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_globalstate; - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_auto, CAutoTrigger ); - -TYPEDESCRIPTION CAutoTrigger::m_SaveData[] = -{ - DEFINE_FIELD( CAutoTrigger, m_globalstate, FIELD_STRING ), - DEFINE_FIELD( CAutoTrigger, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CAutoTrigger,CBaseDelay); - -void CAutoTrigger::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "globalstate")) - { - m_globalstate = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CAutoTrigger::Spawn( void ) -{ - Precache(); -} - - -void CAutoTrigger::Precache( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CAutoTrigger::Think( void ) -{ - if ( !m_globalstate || gGlobalState.EntityGetState( m_globalstate ) == GLOBAL_ON ) - { - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_AUTO_FIREONCE ) - UTIL_Remove( this ); - } -} - - - -#define SF_RELAY_FIREONCE 0x0001 - -class CTriggerRelay : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - USE_TYPE triggerType; -}; -LINK_ENTITY_TO_CLASS( trigger_relay, CTriggerRelay ); - -TYPEDESCRIPTION CTriggerRelay::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerRelay, triggerType, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerRelay,CBaseDelay); - -void CTriggerRelay::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "triggerstate")) - { - int type = atoi( pkvd->szValue ); - switch( type ) - { - case 0: - triggerType = USE_OFF; - break; - case 2: - triggerType = USE_TOGGLE; - break; - default: - triggerType = USE_ON; - break; - } - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - -void CTriggerRelay::Spawn( void ) -{ -} - - - - -void CTriggerRelay::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - SUB_UseTargets( this, triggerType, 0 ); - if ( pev->spawnflags & SF_RELAY_FIREONCE ) - UTIL_Remove( this ); -} - - -//********************************************************** -// The Multimanager Entity - when fired, will fire up to 16 targets -// at specified times. -// FLAG: THREAD (create clones when triggered) -// FLAG: CLONE (this is a clone for a threaded execution) - -#define SF_MULTIMAN_CLONE 0x80000000 -#define SF_MULTIMAN_THREAD 0x00000001 - -class CMultiManager : public CBaseToggle -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn ( void ); - void EXPORT ManagerThink ( void ); - void EXPORT ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - -#if _DEBUG - void EXPORT ManagerReport( void ); -#endif - - BOOL HasTarget( string_t targetname ); - - int ObjectCaps( void ) { return CBaseToggle::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int m_cTargets; // the total number of targets in this manager's fire list. - int m_index; // Current target - float m_startTime;// Time we started firing - int m_iTargetName [ MAX_MULTI_TARGETS ];// list if indexes into global string array - float m_flTargetDelay [ MAX_MULTI_TARGETS ];// delay (in seconds) from time of manager fire to target fire -private: - inline BOOL IsClone( void ) { return (pev->spawnflags & SF_MULTIMAN_CLONE) ? TRUE : FALSE; } - inline BOOL ShouldClone( void ) - { - if ( IsClone() ) - return FALSE; - - return (pev->spawnflags & SF_MULTIMAN_THREAD) ? TRUE : FALSE; - } - - CMultiManager *Clone( void ); -}; -LINK_ENTITY_TO_CLASS( multi_manager, CMultiManager ); - -// Global Savedata for multi_manager -TYPEDESCRIPTION CMultiManager::m_SaveData[] = -{ - DEFINE_FIELD( CMultiManager, m_cTargets, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_index, FIELD_INTEGER ), - DEFINE_FIELD( CMultiManager, m_startTime, FIELD_TIME ), - DEFINE_ARRAY( CMultiManager, m_iTargetName, FIELD_STRING, MAX_MULTI_TARGETS ), - DEFINE_ARRAY( CMultiManager, m_flTargetDelay, FIELD_FLOAT, MAX_MULTI_TARGETS ), -}; - -IMPLEMENT_SAVERESTORE(CMultiManager,CBaseToggle); - -void CMultiManager :: KeyValue( KeyValueData *pkvd ) -{ - // UNDONE: Maybe this should do something like this: - //CBaseToggle::KeyValue( pkvd ); - // if ( !pkvd->fHandled ) - // ... etc. - - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else // add this field to the target list - { - // this assumes that additional fields are targetnames and their values are delay values. - if ( m_cTargets < MAX_MULTI_TARGETS ) - { - char tmp[128]; - - UTIL_StripToken( pkvd->szKeyName, tmp ); - m_iTargetName [ m_cTargets ] = ALLOC_STRING( tmp ); - m_flTargetDelay [ m_cTargets ] = atof (pkvd->szValue); - m_cTargets++; - pkvd->fHandled = TRUE; - } - } -} - - -void CMultiManager :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - SetUse ( &CMultiManager::ManagerUse ); - SetThink ( &CMultiManager::ManagerThink); - - // Sort targets - // Quick and dirty bubble sort - int swapped = 1; - - while ( swapped ) - { - swapped = 0; - for ( int i = 1; i < m_cTargets; i++ ) - { - if ( m_flTargetDelay[i] < m_flTargetDelay[i-1] ) - { - // Swap out of order elements - int name = m_iTargetName[i]; - float delay = m_flTargetDelay[i]; - m_iTargetName[i] = m_iTargetName[i-1]; - m_flTargetDelay[i] = m_flTargetDelay[i-1]; - m_iTargetName[i-1] = name; - m_flTargetDelay[i-1] = delay; - swapped = 1; - } - } - } -} - - -BOOL CMultiManager::HasTarget( string_t targetname ) -{ - for ( int i = 0; i < m_cTargets; i++ ) - if ( FStrEq(STRING(targetname), STRING(m_iTargetName[i])) ) - return TRUE; - - return FALSE; -} - - -// Designers were using this to fire targets that may or may not exist -- -// so I changed it to use the standard target fire code, made it a little simpler. -void CMultiManager :: ManagerThink ( void ) -{ - float time; - - time = gpGlobals->time - m_startTime; - while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time ) - { - FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 ); - m_index++; - } - - if ( m_index >= m_cTargets )// have we fired all targets? - { - SetThink( NULL ); - if ( IsClone() ) - { - UTIL_Remove( this ); - return; - } - SetUse ( &CMultiManager::ManagerUse );// allow manager re-use - } - else - pev->nextthink = m_startTime + m_flTargetDelay[ m_index ]; -} - -CMultiManager *CMultiManager::Clone( void ) -{ - CMultiManager *pMulti = GetClassPtr( (CMultiManager *)NULL ); - - edict_t *pEdict = pMulti->pev->pContainingEntity; - memcpy( pMulti->pev, pev, sizeof(*pev) ); - pMulti->pev->pContainingEntity = pEdict; - - pMulti->pev->spawnflags |= SF_MULTIMAN_CLONE; - pMulti->m_cTargets = m_cTargets; - memcpy( pMulti->m_iTargetName, m_iTargetName, sizeof( m_iTargetName ) ); - memcpy( pMulti->m_flTargetDelay, m_flTargetDelay, sizeof( m_flTargetDelay ) ); - - return pMulti; -} - - -// The USE function builds the time table and starts the entity thinking. -void CMultiManager :: ManagerUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // In multiplayer games, clone the MM and execute in the clone (like a thread) - // to allow multiple players to trigger the same multimanager - if ( ShouldClone() ) - { - CMultiManager *pClone = Clone(); - pClone->ManagerUse( pActivator, pCaller, useType, value ); - return; - } - - m_hActivator = pActivator; - m_index = 0; - m_startTime = gpGlobals->time; - - SetUse( NULL );// disable use until all targets have fired - - SetThink ( &CMultiManager::ManagerThink ); - pev->nextthink = gpGlobals->time; -} - -#if _DEBUG -void CMultiManager :: ManagerReport ( void ) -{ - int cIndex; - - for ( cIndex = 0 ; cIndex < m_cTargets ; cIndex++ ) - { - ALERT ( at_console, "%s %f\n", STRING(m_iTargetName[cIndex]), m_flTargetDelay[cIndex] ); - } -} -#endif - -//*********************************************************** - - -// -// Render parameters trigger -// -// This entity will copy its render parameters (renderfx, rendermode, rendercolor, renderamt) -// to its targets when triggered. -// - - -// Flags to indicate masking off various render parameters that are normally copied to the targets -#define SF_RENDER_MASKFX (1<<0) -#define SF_RENDER_MASKAMT (1<<1) -#define SF_RENDER_MASKMODE (1<<2) -#define SF_RENDER_MASKCOLOR (1<<3) - -class CRenderFxManager : public CBaseEntity -{ -public: - void Spawn( void ); - void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( env_render, CRenderFxManager ); - - -void CRenderFxManager :: Spawn ( void ) -{ - pev->solid = SOLID_NOT; -} - -void CRenderFxManager :: Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (!FStringNull(pev->target)) - { - edict_t* pentTarget = NULL; - while ( 1 ) - { - pentTarget = FIND_ENTITY_BY_TARGETNAME(pentTarget, STRING(pev->target)); - if (FNullEnt(pentTarget)) - break; - - entvars_t *pevTarget = VARS( pentTarget ); - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKFX ) ) - pevTarget->renderfx = pev->renderfx; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKAMT ) ) - pevTarget->renderamt = pev->renderamt; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKMODE ) ) - pevTarget->rendermode = pev->rendermode; - if ( !FBitSet( pev->spawnflags, SF_RENDER_MASKCOLOR ) ) - pevTarget->rendercolor = pev->rendercolor; - } - } -} - - - -class CBaseTrigger : public CBaseToggle -{ -public: - void EXPORT TeleportTouch ( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT MultiTouch( CBaseEntity *pOther ); - void EXPORT HurtTouch ( CBaseEntity *pOther ); - void EXPORT CDAudioTouch ( CBaseEntity *pOther ); - void ActivateMultiTrigger( CBaseEntity *pActivator ); - void EXPORT MultiWaitOver( void ); - void EXPORT CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void InitTrigger( void ); - - virtual int ObjectCaps( void ) { return CBaseToggle :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; - -LINK_ENTITY_TO_CLASS( trigger, CBaseTrigger ); - -/* -================ -InitTrigger -================ -*/ -void CBaseTrigger::InitTrigger( ) -{ - // trigger angles are used for one-way touches. An angle of 0 is assumed - // to mean no restrictions, so use a yaw of 360 instead. - if (pev->angles != g_vecZero) - SetMovedir(pev); - pev->solid = SOLID_TRIGGER; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - if ( CVAR_GET_FLOAT("showtriggers") == 0 ) - SetBits( pev->effects, EF_NODRAW ); -} - - -// -// Cache user-entity-field values until spawn is called. -// - -void CBaseTrigger :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "damage")) - { - pev->dmg = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "count")) - { - m_cTriggersLeft = (int) atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "damagetype")) - { - m_bitsDamageInflict = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseToggle::KeyValue( pkvd ); -} - -class CTriggerHurt : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT RadiationThink( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_hurt, CTriggerHurt ); - -// -// trigger_monsterjump -// -class CTriggerMonsterJump : public CBaseTrigger -{ -public: - void Spawn( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_monsterjump, CTriggerMonsterJump ); - - -void CTriggerMonsterJump :: Spawn ( void ) -{ - SetMovedir ( pev ); - - InitTrigger (); - - pev->nextthink = 0; - pev->speed = 200; - m_flHeight = 150; - - if ( !FStringNull ( pev->targetname ) ) - {// if targetted, spawn turned off - pev->solid = SOLID_NOT; - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetUse( &CTriggerMonsterJump::ToggleUse ); - } -} - - -void CTriggerMonsterJump :: Think( void ) -{ - pev->solid = SOLID_NOT;// kill the trigger for now !!!UNDONE - UTIL_SetOrigin( pev, pev->origin ); // Unlink from trigger list - SetThink( NULL ); -} - -void CTriggerMonsterJump :: Touch( CBaseEntity *pOther ) -{ - entvars_t *pevOther = pOther->pev; - - if ( !FBitSet ( pevOther->flags , FL_MONSTER ) ) - {// touched by a non-monster. - return; - } - - pevOther->origin.z += 1; - - if ( FBitSet ( pevOther->flags, FL_ONGROUND ) ) - {// clear the onground so physics don't bitch - pevOther->flags &= ~FL_ONGROUND; - } - - // toss the monster! - pevOther->velocity = pev->movedir * pev->speed; - pevOther->velocity.z += m_flHeight; - pev->nextthink = gpGlobals->time; -} - - -//===================================== -// -// trigger_cdaudio - starts/stops cd audio tracks -// -class CTriggerCDAudio : public CBaseTrigger -{ -public: - void Spawn( void ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void PlayTrack( void ); - void Touch ( CBaseEntity *pOther ); -}; - -LINK_ENTITY_TO_CLASS( trigger_cdaudio, CTriggerCDAudio ); - -// -// Changes tracks or stops CD when player touches -// -// !!!HACK - overloaded HEALTH to avoid adding new field -void CTriggerCDAudio :: Touch ( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - {// only clients may trigger these events - return; - } - - PlayTrack(); -} - -void CTriggerCDAudio :: Spawn( void ) -{ - InitTrigger(); -} - -void CTriggerCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - PlayTrack(); -} - -void PlayCDTrack( int iTrack ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - if ( iTrack < -1 || iTrack > 30 ) - { - ALERT ( at_console, "TriggerCDAudio - Track %d out of range\n" ); - return; - } - - if ( iTrack == -1 ) - { - CLIENT_COMMAND ( pClient, "cd stop\n"); - } - else - { - char string [ 64 ]; - - sprintf( string, "cd play %3d\n", iTrack ); - CLIENT_COMMAND ( pClient, string); - } -} - - -// only plays for ONE client, so only use in single play! -void CTriggerCDAudio :: PlayTrack( void ) -{ - PlayCDTrack( (int)pev->health ); - - SetTouch( NULL ); - UTIL_Remove( this ); -} - - -// This plays a CD track when fired or when the player enters it's radius -class CTargetCDAudio : public CPointEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - - virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void Think( void ); - void Play( void ); -}; - -LINK_ENTITY_TO_CLASS( target_cdaudio, CTargetCDAudio ); - -void CTargetCDAudio :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->scale = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CPointEntity::KeyValue( pkvd ); -} - -void CTargetCDAudio :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - - if ( pev->scale > 0 ) - pev->nextthink = gpGlobals->time + 1.0; -} - -void CTargetCDAudio::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - Play(); -} - -// only plays for ONE client, so only use in single play! -void CTargetCDAudio::Think( void ) -{ - edict_t *pClient; - - // manually find the single player. - pClient = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - - // Can't play if the client is not connected! - if ( !pClient ) - return; - - pev->nextthink = gpGlobals->time + 0.5; - - if ( (pClient->v.origin - pev->origin).Length() <= pev->scale ) - Play(); - -} - -void CTargetCDAudio::Play( void ) -{ - PlayCDTrack( (int)pev->health ); - UTIL_Remove(this); -} - -//===================================== - -// -// trigger_hurt - hurts anything that touches it. if the trigger has a targetname, firing it will toggle state -// -//int gfToggleState = 0; // used to determine when all radiation trigger hurts have called 'RadiationThink' - -void CTriggerHurt :: Spawn( void ) -{ - InitTrigger(); - SetTouch ( &CTriggerHurt::HurtTouch ); - - if ( !FStringNull ( pev->targetname ) ) - { - SetUse ( &CTriggerHurt::ToggleUse ); - } - else - { - SetUse ( NULL ); - } - - if (m_bitsDamageInflict & DMG_RADIATION) - { - SetThink ( &CTriggerHurt::RadiationThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.0, 0.5); - } - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_HURT_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - -// trigger hurt that causes radiation will do a radius -// check and set the player's geiger counter level -// according to distance from center of trigger - -void CTriggerHurt :: RadiationThink( void ) -{ - - edict_t *pentPlayer; - CBasePlayer *pPlayer = NULL; - float flRange; - entvars_t *pevTarget; - Vector vecSpot1; - Vector vecSpot2; - Vector vecRange; - Vector origin; - Vector view_ofs; - - // check to see if a player is in pvs - // if not, continue - - // set origin to center of trigger so that this check works - origin = pev->origin; - view_ofs = pev->view_ofs; - - pev->origin = (pev->absmin + pev->absmax) * 0.5; - pev->view_ofs = pev->view_ofs * 0.0; - - pentPlayer = FIND_CLIENT_IN_PVS(edict()); - - pev->origin = origin; - pev->view_ofs = view_ofs; - - // reset origin - - if (!FNullEnt(pentPlayer)) - { - - pPlayer = GetClassPtr( (CBasePlayer *)VARS(pentPlayer)); - - pevTarget = VARS(pentPlayer); - - // get range to player; - - vecSpot1 = (pev->absmin + pev->absmax) * 0.5; - vecSpot2 = (pevTarget->absmin + pevTarget->absmax) * 0.5; - - vecRange = vecSpot1 - vecSpot2; - flRange = vecRange.Length(); - - // if player's current geiger counter range is larger - // than range to this trigger hurt, reset player's - // geiger counter range - - if (pPlayer->m_flgeigerRange >= flRange) - pPlayer->m_flgeigerRange = flRange; - } - - pev->nextthink = gpGlobals->time + 0.25; -} - -// -// ToggleUse - If this is the USE function for a trigger, its state will toggle every time it's fired -// -void CBaseTrigger :: ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if (pev->solid == SOLID_NOT) - {// if the trigger is off, turn it on - pev->solid = SOLID_TRIGGER; - - // Force retouch - gpGlobals->force_retouch++; - } - else - {// turn the trigger off - pev->solid = SOLID_NOT; - } - UTIL_SetOrigin( pev, pev->origin ); -} - -// When touched, a hurt trigger does DMG points of damage each half-second -void CBaseTrigger :: HurtTouch ( CBaseEntity *pOther ) -{ - float fldmg; - - if ( !pOther->pev->takedamage ) - return; - - if ( (pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYTOUCH) && !pOther->IsPlayer() ) - { - // this trigger is only allowed to touch clients, and this ain't a client. - return; - } - - if ( (pev->spawnflags & SF_TRIGGER_HURT_NO_CLIENTS) && pOther->IsPlayer() ) - return; - - // HACKHACK -- In multiplayer, players touch this based on packet receipt. - // So the players who send packets later aren't always hurt. Keep track of - // how much time has passed and whether or not you've touched that player - if ( g_pGameRules->IsMultiplayer() ) - { - if ( pev->dmgtime > gpGlobals->time ) - { - if ( gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // If I've already touched this player (this time), then bail out - if ( pev->impulse & playerMask ) - return; - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - else - { - return; - } - } - } - else - { - // New clock, "un-touch" all players - pev->impulse = 0; - if ( pOther->IsPlayer() ) - { - int playerMask = 1 << (pOther->entindex() - 1); - - // Mark this player as touched - // BUGBUG - There can be only 32 players! - pev->impulse |= playerMask; - } - } - } - else // Original code -- single player - { - if ( pev->dmgtime > gpGlobals->time && gpGlobals->time != pev->pain_finished ) - {// too early to hurt again, and not same frame with a different entity - return; - } - } - - - - // If this is time_based damage (poison, radiation), override the pev->dmg with a - // default for the given damage type. Monsters only take time-based damage - // while touching the trigger. Player continues taking damage for a while after - // leaving the trigger - - fldmg = pev->dmg * 0.5; // 0.5 seconds worth of damage, pev->dmg is damage/second - - - // JAY: Cut this because it wasn't fully realized. Damage is simpler now. -#if 0 - switch (m_bitsDamageInflict) - { - default: break; - case DMG_POISON: fldmg = POISON_DAMAGE/4; break; - case DMG_NERVEGAS: fldmg = NERVEGAS_DAMAGE/4; break; - case DMG_RADIATION: fldmg = RADIATION_DAMAGE/4; break; - case DMG_PARALYZE: fldmg = PARALYZE_DAMAGE/4; break; // UNDONE: cut this? should slow movement to 50% - case DMG_ACID: fldmg = ACID_DAMAGE/4; break; - case DMG_SLOWBURN: fldmg = SLOWBURN_DAMAGE/4; break; - case DMG_SLOWFREEZE: fldmg = SLOWFREEZE_DAMAGE/4; break; - } -#endif - - if ( fldmg < 0 ) - pOther->TakeHealth( -fldmg, m_bitsDamageInflict ); - else - pOther->TakeDamage( pev, pev, fldmg, m_bitsDamageInflict ); - - // Store pain time so we can get all of the other entities on this frame - pev->pain_finished = gpGlobals->time; - - // Apply damage every half second - pev->dmgtime = gpGlobals->time + 0.5;// half second delay until this trigger can hurt toucher again - - - - if ( pev->target ) - { - // trigger has a target it wants to fire. - if ( pev->spawnflags & SF_TRIGGER_HURT_CLIENTONLYFIRE ) - { - // if the toucher isn't a client, don't fire the target! - if ( !pOther->IsPlayer() ) - { - return; - } - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); - if ( pev->spawnflags & SF_TRIGGER_HURT_TARGETONCE ) - pev->target = 0; - } -} - - -/*QUAKED trigger_multiple (.5 .5 .5) ? notouch -Variable sized repeatable trigger. Must be targeted at one or more entities. -If "health" is set, the trigger must be killed to activate each time. -If "delay" is set, the trigger waits some time after activating before firing. -"wait" : Seconds between triggerings. (.2 default) -If notouch is set, the trigger is only fired by other entities, not by touching. -NOTOUCH has been obsoleted by trigger_relay! -sounds -1) secret -2) beep beep -3) large switch -4) -NEW -if a trigger has a NETNAME, that NETNAME will become the TARGET of the triggered object. -*/ -class CTriggerMultiple : public CBaseTrigger -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_multiple, CTriggerMultiple ); - - -void CTriggerMultiple :: Spawn( void ) -{ - if (m_flWait == 0) - m_flWait = 0.2; - - InitTrigger(); - - ASSERTSZ(pev->health == 0, "trigger_multiple with health"); -// UTIL_SetOrigin(pev, pev->origin); -// SET_MODEL( ENT(pev), STRING(pev->model) ); -// if (pev->health > 0) -// { -// if (FBitSet(pev->spawnflags, SPAWNFLAG_NOTOUCH)) -// ALERT(at_error, "trigger_multiple spawn: health and notouch don't make sense"); -// pev->max_health = pev->health; -//UNDONE: where to get pfnDie from? -// pev->pfnDie = multi_killed; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// UTIL_SetOrigin(pev, pev->origin); // make sure it links into the world -// } -// else - { - SetTouch( &CTriggerMultiple::MultiTouch ); - } - } - - -/*QUAKED trigger_once (.5 .5 .5) ? notouch -Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching -"targetname". If "health" is set, the trigger must be killed to activate. -If notouch is set, the trigger is only fired by other entities, not by touching. -if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired. -if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0. -sounds -1) secret -2) beep beep -3) large switch -4) -*/ -class CTriggerOnce : public CTriggerMultiple -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_once, CTriggerOnce ); -void CTriggerOnce::Spawn( void ) -{ - m_flWait = -1; - - CTriggerMultiple :: Spawn(); -} - - - -void CBaseTrigger :: MultiTouch( CBaseEntity *pOther ) -{ - entvars_t *pevToucher; - - pevToucher = pOther->pev; - - // Only touch clients, monsters, or pushables (depending on flags) - if ( ((pevToucher->flags & FL_CLIENT) && !(pev->spawnflags & SF_TRIGGER_NOCLIENTS)) || - ((pevToucher->flags & FL_MONSTER) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS)) || - ((pev->spawnflags & SF_TRIGGER_PUSHABLES) && FClassnameIs(pevToucher,"func_pushable")) ) - { - -#if 0 - // if the trigger has an angles field, check player's facing direction - if (pev->movedir != g_vecZero) - { - UTIL_MakeVectors( pevToucher->angles ); - if ( DotProduct( gpGlobals->v_forward, pev->movedir ) < 0 ) - return; // not facing the right way - } -#endif - - ActivateMultiTrigger( pOther ); - } -} - - -// -// the trigger was just touched/killed/used -// self.enemy should be set to the activator so it can be held through a delay -// so wait for the delay time before firing -// -void CBaseTrigger :: ActivateMultiTrigger( CBaseEntity *pActivator ) -{ - if (pev->nextthink > gpGlobals->time) - return; // still waiting for reset time - - if (!UTIL_IsMasterTriggered(m_sMaster,pActivator)) - return; - - if (FClassnameIs(pev, "trigger_secret")) - { - if ( pev->enemy == NULL || !FClassnameIs(pev->enemy, "player")) - return; - gpGlobals->found_secrets++; - } - - if (!FStringNull(pev->noise)) - EMIT_SOUND(ENT(pev), CHAN_VOICE, (char*)STRING(pev->noise), 1, ATTN_NORM); - -// don't trigger again until reset -// pev->takedamage = DAMAGE_NO; - - m_hActivator = pActivator; - SUB_UseTargets( m_hActivator, USE_TOGGLE, 0 ); - - if ( pev->message && pActivator->IsPlayer() ) - { - UTIL_ShowMessage( STRING(pev->message), pActivator ); -// CLIENT_PRINTF( ENT( pActivator->pev ), print_center, STRING(pev->message) ); - } - - if (m_flWait > 0) - { - SetThink( &CBaseTrigger::MultiWaitOver ); - pev->nextthink = gpGlobals->time + m_flWait; - } - else - { - // we can't just remove (self) here, because this is a touch function - // called while C code is looping through area links... - SetTouch( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - SetThink( &CBaseTrigger::SUB_Remove ); - } -} - - -// the wait time has passed, so set back up for another activation -void CBaseTrigger :: MultiWaitOver( void ) -{ -// if (pev->max_health) -// { -// pev->health = pev->max_health; -// pev->takedamage = DAMAGE_YES; -// pev->solid = SOLID_BBOX; -// } - SetThink( NULL ); -} - - -// ========================= COUNTING TRIGGER ===================================== - -// -// GLOBALS ASSUMED SET: g_eoActivator -// -void CBaseTrigger::CounterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - m_cTriggersLeft--; - m_hActivator = pActivator; - - if (m_cTriggersLeft < 0) - return; - - BOOL fTellActivator = - (m_hActivator != 0) && - FClassnameIs(m_hActivator->pev, "player") && - !FBitSet(pev->spawnflags, SPAWNFLAG_NOMESSAGE); - if (m_cTriggersLeft != 0) - { - if (fTellActivator) - { - // UNDONE: I don't think we want these Quakesque messages - switch (m_cTriggersLeft) - { - case 1: ALERT(at_console, "Only 1 more to go..."); break; - case 2: ALERT(at_console, "Only 2 more to go..."); break; - case 3: ALERT(at_console, "Only 3 more to go..."); break; - default: ALERT(at_console, "There are more to go..."); break; - } - } - return; - } - - // !!!UNDONE: I don't think we want these Quakesque messages - if (fTellActivator) - ALERT(at_console, "Sequence completed!"); - - ActivateMultiTrigger( m_hActivator ); -} - - -/*QUAKED trigger_counter (.5 .5 .5) ? nomessage -Acts as an intermediary for an action that takes multiple inputs. -If nomessage is not set, it will print "1 more.. " etc when triggered and -"sequence complete" when finished. After the counter has been triggered "cTriggersLeft" -times (default 2), it will fire all of it's targets and remove itself. -*/ -class CTriggerCounter : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_counter, CTriggerCounter ); - -void CTriggerCounter :: Spawn( void ) -{ - // By making the flWait be -1, this counter-trigger will disappear after it's activated - // (but of course it needs cTriggersLeft "uses" before that happens). - m_flWait = -1; - - if (m_cTriggersLeft == 0) - m_cTriggersLeft = 2; - SetUse( &CTriggerCounter::CounterUse ); -} - -// ====================== TRIGGER_CHANGELEVEL ================================ - -class CTriggerVolume : public CPointEntity // Derive from point entity so this doesn't move across levels -{ -public: - void Spawn( void ); -}; - -LINK_ENTITY_TO_CLASS( trigger_transition, CTriggerVolume ); - -// Define space that travels across a level transition -void CTriggerVolume :: Spawn( void ) -{ - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->model = 0; - pev->modelindex = 0; -} - - -// Fires a target after level transition and then dies -class CFireAndDie : public CBaseDelay -{ -public: - void Spawn( void ); - void Precache( void ); - void Think( void ); - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() | FCAP_FORCE_TRANSITION; } // Always go across transitions -}; -LINK_ENTITY_TO_CLASS( fireanddie, CFireAndDie ); - -void CFireAndDie::Spawn( void ) -{ - pev->classname = MAKE_STRING("fireanddie"); - // Don't call Precache() - it should be called on restore -} - - -void CFireAndDie::Precache( void ) -{ - // This gets called on restore - pev->nextthink = gpGlobals->time + m_flDelay; -} - - -void CFireAndDie::Think( void ) -{ - SUB_UseTargets( this, USE_TOGGLE, 0 ); - UTIL_Remove( this ); -} - - -#define SF_CHANGELEVEL_USEONLY 0x0002 -class CChangeLevel : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TriggerChangeLevel( void ); - void EXPORT ExecuteChangeLevel( void ); - void EXPORT TouchChangeLevel( CBaseEntity *pOther ); - void ChangeLevelNow( CBaseEntity *pActivator ); - - static edict_t *FindLandmark( const char *pLandmarkName ); - static int ChangeList( LEVELLIST *pLevelList, int maxList ); - static int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ); - static int InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - char m_szMapName[cchMapNameMost]; // trigger_changelevel only: next map - char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map - int m_changeTarget; - float m_changeTargetDelay; -}; -LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ); - -// Global Savedata for changelevel trigger -TYPEDESCRIPTION CChangeLevel::m_SaveData[] = -{ - DEFINE_ARRAY( CChangeLevel, m_szMapName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_ARRAY( CChangeLevel, m_szLandmarkName, FIELD_CHARACTER, cchMapNameMost ), - DEFINE_FIELD( CChangeLevel, m_changeTarget, FIELD_STRING ), - DEFINE_FIELD( CChangeLevel, m_changeTargetDelay, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE(CChangeLevel,CBaseTrigger); - -// -// Cache user-entity-field values until spawn is called. -// - -void CChangeLevel :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "map")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szMapName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "landmark")) - { - if (strlen(pkvd->szValue) >= cchMapNameMost) - ALERT( at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue ); - strcpy(m_szLandmarkName, pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changetarget")) - { - m_changeTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "changedelay")) - { - m_changeTargetDelay = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION -When the player touches this, he gets sent to the map listed in the "map" variable. Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission spot and display stats. -*/ - -void CChangeLevel :: Spawn( void ) -{ - if ( FStrEq( m_szMapName, "" ) ) - ALERT( at_console, "a trigger_changelevel doesn't have a map" ); - - if ( FStrEq( m_szLandmarkName, "" ) ) - ALERT( at_console, "trigger_changelevel to %s doesn't have a landmark", m_szMapName ); - - if (!FStringNull ( pev->targetname ) ) - { - SetUse ( &CChangeLevel::UseChangeLevel ); - } - InitTrigger(); - if ( !(pev->spawnflags & SF_CHANGELEVEL_USEONLY) ) - SetTouch( &CChangeLevel::TouchChangeLevel ); -// ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); -} - - -void CChangeLevel :: ExecuteChangeLevel( void ) -{ - MESSAGE_BEGIN( MSG_ALL, SVC_CDTRACK ); - WRITE_BYTE( 3 ); - WRITE_BYTE( 3 ); - MESSAGE_END(); - - MESSAGE_BEGIN(MSG_ALL, SVC_INTERMISSION); - MESSAGE_END(); -} - - -FILE_GLOBAL char st_szNextMap[cchMapNameMost]; -FILE_GLOBAL char st_szNextSpot[cchMapNameMost]; - -edict_t *CChangeLevel :: FindLandmark( const char *pLandmarkName ) -{ - edict_t *pentLandmark; - - pentLandmark = FIND_ENTITY_BY_STRING( NULL, "targetname", pLandmarkName ); - while ( !FNullEnt( pentLandmark ) ) - { - // Found the landmark - if ( FClassnameIs( pentLandmark, "info_landmark" ) ) - return pentLandmark; - else - pentLandmark = FIND_ENTITY_BY_STRING( pentLandmark, "targetname", pLandmarkName ); - } - ALERT( at_error, "Can't find landmark %s\n", pLandmarkName ); - return NULL; -} - - -//========================================================= -// CChangeLevel :: Use - allows level transitions to be -// triggered by buttons, etc. -// -//========================================================= -void CChangeLevel :: UseChangeLevel ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - ChangeLevelNow( pActivator ); -} - -void CChangeLevel :: ChangeLevelNow( CBaseEntity *pActivator ) -{ - edict_t *pentLandmark; - - ASSERT(!FStrEq(m_szMapName, "")); - - // Don't work in deathmatch - if ( g_pGameRules->IsDeathmatch() ) - return; - - // Some people are firing these multiple times in a frame, disable - if ( gpGlobals->time == pev->dmgtime ) - return; - - pev->dmgtime = gpGlobals->time; - - - CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) ); - if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) ) - { - ALERT( at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); - return; - } - - // Create an entity to fire the changetarget - if ( m_changeTarget ) - { - CFireAndDie *pFireAndDie = GetClassPtr( (CFireAndDie *)NULL ); - if ( pFireAndDie ) - { - // Set target and delay - pFireAndDie->pev->target = m_changeTarget; - pFireAndDie->m_flDelay = m_changeTargetDelay; - pFireAndDie->pev->origin = pPlayer->pev->origin; - // Call spawn - DispatchSpawn( pFireAndDie->edict() ); - } - } - // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy(st_szNextMap, m_szMapName); - - m_hActivator = pActivator; - SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); - st_szNextSpot[0] = 0; // Init landmark to NULL - - // look for a landmark entity - pentLandmark = FindLandmark( m_szLandmarkName ); - if ( !FNullEnt( pentLandmark ) ) - { - strcpy(st_szNextSpot, m_szLandmarkName); - gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; - } -// ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); - ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); - CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); -} - -// -// GLOBALS ASSUMED SET: st_szNextMap -// -void CChangeLevel :: TouchChangeLevel( CBaseEntity *pOther ) -{ - if (!FClassnameIs(pOther->pev, "player")) - return; - - ChangeLevelNow( pOther ); -} - - -// Add a transition to the list, but ignore duplicates -// (a designer may have placed multiple trigger_changelevels with the same landmark) -int CChangeLevel::AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) -{ - int i; - - if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) - return 0; - - for ( i = 0; i < listCount; i++ ) - { - if ( pLevelList[i].pentLandmark == pentLandmark && strcmp( pLevelList[i].mapName, pMapName ) == 0 ) - return 0; - } - strcpy( pLevelList[listCount].mapName, pMapName ); - strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); - pLevelList[listCount].pentLandmark = pentLandmark; - pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; - - return 1; -} - -int BuildChangeList( LEVELLIST *pLevelList, int maxList ) -{ - return CChangeLevel::ChangeList( pLevelList, maxList ); -} - - -int CChangeLevel::InTransitionVolume( CBaseEntity *pEntity, char *pVolumeName ) -{ - edict_t *pentVolume; - - - if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) - return 1; - - // If you're following another entity, follow it through the transition (weapons follow the player) - if ( pEntity->pev->movetype == MOVETYPE_FOLLOW ) - { - if ( pEntity->pev->aiment != NULL ) - pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); - } - - int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume - - pentVolume = FIND_ENTITY_BY_TARGETNAME( NULL, pVolumeName ); - while ( !FNullEnt( pentVolume ) ) - { - CBaseEntity *pVolume = CBaseEntity::Instance( pentVolume ); - - if ( pVolume && FClassnameIs( pVolume->pev, "trigger_transition" ) ) - { - if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume - return 1; - else - inVolume = 0; // Found a trigger_transition, but I don't intersect it -- if I don't find another, don't go! - } - pentVolume = FIND_ENTITY_BY_TARGETNAME( pentVolume, pVolumeName ); - } - - return inVolume; -} - - -// We can only ever move 512 entities across a transition -#define MAX_ENTITY 512 - -// This has grown into a complicated beast -// Can we make this more elegant? -// This builds the list of all transitions on this level and which entities are in their PVS's and can / should -// be moved across. -int CChangeLevel::ChangeList( LEVELLIST *pLevelList, int maxList ) -{ - edict_t *pentChangelevel, *pentLandmark; - int i, count; - - count = 0; - - // Find all of the possible level changes on this BSP - pentChangelevel = FIND_ENTITY_BY_STRING( NULL, "classname", "trigger_changelevel" ); - if ( FNullEnt( pentChangelevel ) ) - return 0; - while ( !FNullEnt( pentChangelevel ) ) - { - CChangeLevel *pTrigger; - - pTrigger = GetClassPtr((CChangeLevel *)VARS(pentChangelevel)); - if ( pTrigger ) - { - // Find the corresponding landmark - pentLandmark = FindLandmark( pTrigger->m_szLandmarkName ); - if ( pentLandmark ) - { - // Build a list of unique transitions - if ( AddTransitionToList( pLevelList, count, pTrigger->m_szMapName, pTrigger->m_szLandmarkName, pentLandmark ) ) - { - count++; - if ( count >= maxList ) // FULL!! - break; - } - } - } - pentChangelevel = FIND_ENTITY_BY_STRING( pentChangelevel, "classname", "trigger_changelevel" ); - } - - if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) - { - CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); - - for ( i = 0; i < count; i++ ) - { - int j, entityCount = 0; - CBaseEntity *pEntList[ MAX_ENTITY ]; - int entityFlags[ MAX_ENTITY ]; - - // Follow the linked list of entities in the PVS of the transition landmark - edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); - - // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) - while ( !FNullEnt( pent ) ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if ( pEntity ) - { -// ALERT( at_console, "Trying %s\n", STRING(pEntity->pev->classname) ); - int caps = pEntity->ObjectCaps(); - if ( !(caps & FCAP_DONT_SAVE) ) - { - int flags = 0; - - // If this entity can be moved or is global, mark it - if ( caps & FCAP_ACROSS_TRANSITION ) - flags |= FENTTABLE_MOVEABLE; - if ( pEntity->pev->globalname && !pEntity->IsDormant() ) - flags |= FENTTABLE_GLOBAL; - if ( flags ) - { - pEntList[ entityCount ] = pEntity; - entityFlags[ entityCount ] = flags; - entityCount++; - if ( entityCount > MAX_ENTITY ) - ALERT( at_error, "Too many entities across a transition!" ); - } -// else -// ALERT( at_console, "Failed %s\n", STRING(pEntity->pev->classname) ); - } -// else -// ALERT( at_console, "DON'T SAVE %s\n", STRING(pEntity->pev->classname) ); - } - pent = pent->v.chain; - } - - for ( j = 0; j < entityCount; j++ ) - { - // Check to make sure the entity isn't screened out by a trigger_transition - if ( entityFlags[j] && InTransitionVolume( pEntList[j], pLevelList[i].landmarkName ) ) - { - // Mark entity table with 1<pev->classname) ); - - } - } - } - - return count; -} - -/* -go to the next level for deathmatch -only called if a time or frag limit has expired -*/ -void NextLevel( void ) -{ - edict_t* pent; - CChangeLevel *pChange; - - // find a trigger_changelevel - pent = FIND_ENTITY_BY_CLASSNAME(NULL, "trigger_changelevel"); - - // go back to start if no trigger_changelevel - if (FNullEnt(pent)) - { - gpGlobals->mapname = ALLOC_STRING("start"); - pChange = GetClassPtr( (CChangeLevel *)NULL ); - strcpy(pChange->m_szMapName, "start"); - } - else - pChange = GetClassPtr( (CChangeLevel *)VARS(pent)); - - strcpy(st_szNextMap, pChange->m_szMapName); - g_fGameOver = TRUE; - - if (pChange->pev->nextthink < gpGlobals->time) - { - pChange->SetThink( &CChangeLevel::ExecuteChangeLevel ); - pChange->pev->nextthink = gpGlobals->time + 0.1; - } -} - - -// ============================== LADDER ======================================= - -class CLadder : public CBaseTrigger -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Precache( void ); -}; -LINK_ENTITY_TO_CLASS( func_ladder, CLadder ); - - -void CLadder :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -//========================================================= -// func_ladder - makes an area vertically negotiable -//========================================================= -void CLadder :: Precache( void ) -{ - // Do all of this in here because we need to 'convert' old saved games - pev->solid = SOLID_NOT; - pev->skin = CONTENTS_LADDER; - if ( CVAR_GET_FLOAT("showtriggers") == 0 ) - { - pev->rendermode = kRenderTransTexture; - pev->renderamt = 0; - } - pev->effects &= ~EF_NODRAW; -} - - -void CLadder :: Spawn( void ) -{ - Precache(); - - SET_MODEL(ENT(pev), STRING(pev->model)); // set size and link into world - pev->movetype = MOVETYPE_PUSH; -} - - -// ========================== A TRIGGER THAT PUSHES YOU =============================== - -class CTriggerPush : public CBaseTrigger -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Touch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_push, CTriggerPush ); - - -void CTriggerPush :: KeyValue( KeyValueData *pkvd ) -{ - CBaseTrigger::KeyValue( pkvd ); -} - - -/*QUAKED trigger_push (.5 .5 .5) ? TRIG_PUSH_ONCE -Pushes the player -*/ - -void CTriggerPush :: Spawn( ) -{ - if ( pev->angles == g_vecZero ) - pev->angles.y = 360; - InitTrigger(); - - if (pev->speed == 0) - pev->speed = 100; - - if ( FBitSet (pev->spawnflags, SF_TRIGGER_PUSH_START_OFF) )// if flagged to Start Turned Off, make trigger nonsolid. - pev->solid = SOLID_NOT; - - SetUse( &CTriggerPush::ToggleUse ); - - UTIL_SetOrigin( pev, pev->origin ); // Link into the list -} - - -void CTriggerPush :: Touch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - - // UNDONE: Is there a better way than health to detect things that have physics? (clients/monsters) - switch( pevToucher->movetype ) - { - case MOVETYPE_NONE: - case MOVETYPE_PUSH: - case MOVETYPE_NOCLIP: - case MOVETYPE_FOLLOW: - return; - } - - if ( pevToucher->solid != SOLID_NOT && pevToucher->solid != SOLID_BSP ) - { - // Instant trigger, just transfer velocity and remove - if (FBitSet(pev->spawnflags, SF_TRIG_PUSH_ONCE)) - { - pevToucher->velocity = pevToucher->velocity + (pev->speed * pev->movedir); - if ( pevToucher->velocity.z > 0 ) - pevToucher->flags &= ~FL_ONGROUND; - UTIL_Remove( this ); - } - else - { // Push field, transfer to base velocity - Vector vecPush = (pev->speed * pev->movedir); - if ( pevToucher->flags & FL_BASEVELOCITY ) - vecPush = vecPush + pevToucher->basevelocity; - - pevToucher->basevelocity = vecPush; - - pevToucher->flags |= FL_BASEVELOCITY; -// ALERT( at_console, "Vel %f, base %f\n", pevToucher->velocity.z, pevToucher->basevelocity.z ); - } - } -} - - -//====================================== -// teleport trigger -// -// - -void CBaseTrigger :: TeleportTouch( CBaseEntity *pOther ) -{ - entvars_t* pevToucher = pOther->pev; - edict_t *pentTarget = NULL; - - // Only teleport monsters or clients - if ( !FBitSet( pevToucher->flags, FL_CLIENT|FL_MONSTER ) ) - return; - - if (!UTIL_IsMasterTriggered(m_sMaster, pOther)) - return; - - if ( !( pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) - {// no monsters allowed! - if ( FBitSet( pevToucher->flags, FL_MONSTER ) ) - { - return; - } - } - - if ( ( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) - {// no clients allowed - if ( pOther->IsPlayer() ) - { - return; - } - } - - pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, STRING(pev->target) ); - if (FNullEnt(pentTarget)) - return; - - Vector tmp = VARS( pentTarget )->origin; - - if ( pOther->IsPlayer() ) - { - tmp.z -= pOther->pev->mins.z;// make origin adjustments in case the teleportee is a player. (origin in center, not at feet) - } - - tmp.z++; - - pevToucher->flags &= ~FL_ONGROUND; - - UTIL_SetOrigin( pevToucher, tmp ); - - pevToucher->angles = pentTarget->v.angles; - - if ( pOther->IsPlayer() ) - { - pevToucher->v_angle = pentTarget->v.angles; - } - - pevToucher->fixangle = TRUE; - pevToucher->velocity = pevToucher->basevelocity = g_vecZero; -} - - -class CTriggerTeleport : public CBaseTrigger -{ -public: - void Spawn( void ); -}; -LINK_ENTITY_TO_CLASS( trigger_teleport, CTriggerTeleport ); - -void CTriggerTeleport :: Spawn( void ) -{ - InitTrigger(); - - SetTouch( &CTriggerTeleport::TeleportTouch ); -} - - -LINK_ENTITY_TO_CLASS( info_teleport_destination, CPointEntity ); - - - -class CTriggerSave : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT SaveTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_autosave, CTriggerSave ); - -void CTriggerSave::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - SetTouch( &CTriggerSave::SaveTouch ); -} - -void CTriggerSave::SaveTouch( CBaseEntity *pOther ) -{ - if ( !UTIL_IsMasterTriggered( m_sMaster, pOther ) ) - return; - - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - SetTouch( NULL ); - UTIL_Remove( this ); - SERVER_COMMAND( "autosave\n" ); -} - -#define SF_ENDSECTION_USEONLY 0x0001 - -class CTriggerEndSection : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT EndSectionTouch( CBaseEntity *pOther ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; -LINK_ENTITY_TO_CLASS( trigger_endsection, CTriggerEndSection ); - - -void CTriggerEndSection::EndSectionUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // Only save on clients - if ( pActivator && !pActivator->IsNetClient() ) - return; - - SetUse( NULL ); - - if ( pev->message ) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection::Spawn( void ) -{ - if ( g_pGameRules->IsDeathmatch() ) - { - REMOVE_ENTITY( ENT(pev) ); - return; - } - - InitTrigger(); - - SetUse ( &CTriggerEndSection::EndSectionUse ); - // If it is a "use only" trigger, then don't set the touch function. - if ( ! (pev->spawnflags & SF_ENDSECTION_USEONLY) ) - SetTouch( &CTriggerEndSection::EndSectionTouch ); -} - -void CTriggerEndSection::EndSectionTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsNetClient() ) - return; - - SetTouch( NULL ); - - if (pev->message) - { - g_engfuncs.pfnEndSection(STRING(pev->message)); - } - UTIL_Remove( this ); -} - -void CTriggerEndSection :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "section")) - { -// m_iszSectionName = ALLOC_STRING( pkvd->szValue ); - // Store this in message so we don't have to write save/restore for this ent - pev->message = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseTrigger::KeyValue( pkvd ); -} - - -class CTriggerGravity : public CBaseTrigger -{ -public: - void Spawn( void ); - void EXPORT GravityTouch( CBaseEntity *pOther ); -}; -LINK_ENTITY_TO_CLASS( trigger_gravity, CTriggerGravity ); - -void CTriggerGravity::Spawn( void ) -{ - InitTrigger(); - SetTouch( &CTriggerGravity::GravityTouch ); -} - -void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) -{ - // Only save on clients - if ( !pOther->IsPlayer() ) - return; - - pOther->pev->gravity = pev->gravity; -} - - - - - - - -// this is a really bad idea. -class CTriggerChangeTarget : public CBaseDelay -{ -public: - void KeyValue( KeyValueData *pkvd ); - void Spawn( void ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - -private: - int m_iszNewTarget; -}; -LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget ); - -TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerChangeTarget, m_iszNewTarget, FIELD_STRING ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerChangeTarget,CBaseDelay); - -void CTriggerChangeTarget::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "m_iszNewTarget")) - { - m_iszNewTarget = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - -void CTriggerChangeTarget::Spawn( void ) -{ -} - - -void CTriggerChangeTarget::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - CBaseEntity *pTarget = UTIL_FindEntityByString( NULL, "targetname", STRING( pev->target ) ); - - if (pTarget) - { - pTarget->pev->target = m_iszNewTarget; - CBaseMonster *pMonster = pTarget->MyMonsterPointer( ); - if (pMonster) - { - pMonster->m_pGoalEnt = NULL; - } - } -} - - - - -#define SF_CAMERA_PLAYER_POSITION 1 -#define SF_CAMERA_PLAYER_TARGET 2 -#define SF_CAMERA_PLAYER_TAKECONTROL 4 - -class CTriggerCamera : public CBaseDelay -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT FollowTarget( void ); - void Move(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - static TYPEDESCRIPTION m_SaveData[]; - - EHANDLE m_hPlayer; - EHANDLE m_hTarget; - CBaseEntity *m_pentPath; - int m_sPath; - float m_flWait; - float m_flReturnTime; - float m_flStopTime; - float m_moveDistance; - float m_targetSpeed; - float m_initialSpeed; - float m_acceleration; - float m_deceleration; - int m_state; - -}; -LINK_ENTITY_TO_CLASS( trigger_camera, CTriggerCamera ); - -// Global Savedata for changelevel friction modifier -TYPEDESCRIPTION CTriggerCamera::m_SaveData[] = -{ - DEFINE_FIELD( CTriggerCamera, m_hPlayer, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_hTarget, FIELD_EHANDLE ), - DEFINE_FIELD( CTriggerCamera, m_pentPath, FIELD_CLASSPTR ), - DEFINE_FIELD( CTriggerCamera, m_sPath, FIELD_STRING ), - DEFINE_FIELD( CTriggerCamera, m_flWait, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_flReturnTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_flStopTime, FIELD_TIME ), - DEFINE_FIELD( CTriggerCamera, m_moveDistance, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_targetSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_initialSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_acceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_deceleration, FIELD_FLOAT ), - DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE(CTriggerCamera,CBaseDelay); - -void CTriggerCamera::Spawn( void ) -{ - pev->movetype = MOVETYPE_NOCLIP; - pev->solid = SOLID_NOT; // Remove model & collisions - pev->renderamt = 0; // The engine won't draw this model if this is set to 0 and blending is on - pev->rendermode = kRenderTransTexture; - - m_initialSpeed = pev->speed; - if ( m_acceleration == 0 ) - m_acceleration = 500; - if ( m_deceleration == 0 ) - m_deceleration = 500; -} - - -void CTriggerCamera :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "wait")) - { - m_flWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "moveto")) - { - m_sPath = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "acceleration")) - { - m_acceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "deceleration")) - { - m_deceleration = atof( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else - CBaseDelay::KeyValue( pkvd ); -} - - - -void CTriggerCamera::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_state ) ) - return; - - // Toggle state - m_state = !m_state; - if (m_state == 0) - { - m_flReturnTime = gpGlobals->time; - return; - } - if ( !pActivator || !pActivator->IsPlayer() ) - { - pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); - } - - m_hPlayer = pActivator; - - m_flReturnTime = gpGlobals->time + m_flWait; - pev->speed = m_initialSpeed; - m_targetSpeed = m_initialSpeed; - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TARGET ) ) - { - m_hTarget = m_hPlayer; - } - else - { - m_hTarget = GetNextTarget(); - } - - // Nothing to look at! - if ( m_hTarget == 0 ) - { - return; - } - - - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL ) ) - { - ((CBasePlayer *)pActivator)->EnableControl(FALSE); - } - - if ( m_sPath ) - { - m_pentPath = Instance( FIND_ENTITY_BY_TARGETNAME ( NULL, STRING(m_sPath)) ); - } - else - { - m_pentPath = NULL; - } - - m_flStopTime = gpGlobals->time; - if ( m_pentPath ) - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - m_flStopTime += m_pentPath->GetDelay(); - } - - // copy over player information - if (FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_POSITION ) ) - { - UTIL_SetOrigin( pev, pActivator->pev->origin + pActivator->pev->view_ofs ); - pev->angles.x = -pActivator->pev->angles.x; - pev->angles.y = pActivator->pev->angles.y; - pev->angles.z = 0; - pev->velocity = pActivator->pev->velocity; - } - else - { - pev->velocity = Vector( 0, 0, 0 ); - } - - SET_VIEW( pActivator->edict(), edict() ); - - SET_MODEL(ENT(pev), STRING(pActivator->pev->model) ); - - // follow the player down - SetThink( &CTriggerCamera::FollowTarget ); - pev->nextthink = gpGlobals->time; - - m_moveDistance = 0; - Move(); -} - - -void CTriggerCamera::FollowTarget( ) -{ - if (m_hPlayer == 0) - return; - - if (m_hTarget == 0 || m_flReturnTime < gpGlobals->time) - { - if (m_hPlayer->IsAlive( )) - { - SET_VIEW( m_hPlayer->edict(), m_hPlayer->edict() ); - ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE); - } - SUB_UseTargets( this, USE_TOGGLE, 0 ); - pev->avelocity = Vector( 0, 0, 0 ); - m_state = 0; - return; - } - - Vector vecGoal = UTIL_VecToAngles( m_hTarget->pev->origin - pev->origin ); - vecGoal.x = -vecGoal.x; - - if (pev->angles.y > 360) - pev->angles.y -= 360; - - if (pev->angles.y < 0) - pev->angles.y += 360; - - float dx = vecGoal.x - pev->angles.x; - float dy = vecGoal.y - pev->angles.y; - - if (dx < -180) - dx += 360; - if (dx > 180) - dx = dx - 360; - - if (dy < -180) - dy += 360; - if (dy > 180) - dy = dy - 360; - - pev->avelocity.x = dx * 40 * gpGlobals->frametime; - pev->avelocity.y = dy * 40 * gpGlobals->frametime; - - - if (!(FBitSet (pev->spawnflags, SF_CAMERA_PLAYER_TAKECONTROL))) - { - pev->velocity = pev->velocity * 0.8; - if (pev->velocity.Length( ) < 10.0) - pev->velocity = g_vecZero; - } - - pev->nextthink = gpGlobals->time; - - Move(); -} - -void CTriggerCamera::Move() -{ - // Not moving on a path, return - if (!m_pentPath) - return; - - // Subtract movement from the previous frame - m_moveDistance -= pev->speed * gpGlobals->frametime; - - // Have we moved enough to reach the target? - if ( m_moveDistance <= 0 ) - { - // Fire the passtarget if there is one - if ( m_pentPath->pev->message ) - { - FireTargets( STRING(m_pentPath->pev->message), this, this, USE_TOGGLE, 0 ); - if ( FBitSet( m_pentPath->pev->spawnflags, SF_CORNER_FIREONCE ) ) - m_pentPath->pev->message = 0; - } - // Time to go to the next target - m_pentPath = m_pentPath->GetNextTarget(); - - // Set up next corner - if ( !m_pentPath ) - { - pev->velocity = g_vecZero; - } - else - { - if ( m_pentPath->pev->speed != 0 ) - m_targetSpeed = m_pentPath->pev->speed; - - Vector delta = m_pentPath->pev->origin - pev->origin; - m_moveDistance = delta.Length(); - pev->movedir = delta.Normalize(); - m_flStopTime = gpGlobals->time + m_pentPath->GetDelay(); - } - } - - if ( m_flStopTime > gpGlobals->time ) - pev->speed = UTIL_Approach( 0, pev->speed, m_deceleration * gpGlobals->frametime ); - else - pev->speed = UTIL_Approach( m_targetSpeed, pev->speed, m_acceleration * gpGlobals->frametime ); - - float fraction = 2 * gpGlobals->frametime; - pev->velocity = ((pev->movedir * pev->speed) * fraction) + (pev->velocity * (1-fraction)); -} diff --git a/sdk/dlls/tripmine.cpp b/sdk/dlls/tripmine.cpp deleted file mode 100644 index 97376f3..0000000 --- a/sdk/dlls/tripmine.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" -#include "effects.h" -#include "gamerules.h" - -#define TRIPMINE_PRIMARY_VOLUME 450 - - - -enum tripmine_e { - TRIPMINE_IDLE1 = 0, - TRIPMINE_IDLE2, - TRIPMINE_ARM1, - TRIPMINE_ARM2, - TRIPMINE_FIDGET, - TRIPMINE_HOLSTER, - TRIPMINE_DRAW, - TRIPMINE_WORLD, - TRIPMINE_GROUND, -}; - - -#ifndef CLIENT_DLL - -class CTripmineGrenade : public CGrenade -{ - void Spawn( void ); - void Precache( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - - void EXPORT WarningThink( void ); - void EXPORT PowerupThink( void ); - void EXPORT BeamBreakThink( void ); - void EXPORT DelayDeathThink( void ); - void Killed( entvars_t *pevAttacker, int iGib ); - - void MakeBeam( void ); - void KillBeam( void ); - - float m_flPowerUp; - Vector m_vecDir; - Vector m_vecEnd; - float m_flBeamLength; - - EHANDLE m_hOwner; - CBeam *m_pBeam; - Vector m_posOwner; - Vector m_angleOwner; - edict_t *m_pRealOwner;// tracelines don't hit PEV->OWNER, which means a player couldn't detonate his own trip mine, so we store the owner here. -}; - -LINK_ENTITY_TO_CLASS( monster_tripmine, CTripmineGrenade ); - -TYPEDESCRIPTION CTripmineGrenade::m_SaveData[] = -{ - DEFINE_FIELD( CTripmineGrenade, m_flPowerUp, FIELD_TIME ), - DEFINE_FIELD( CTripmineGrenade, m_vecDir, FIELD_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_vecEnd, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_flBeamLength, FIELD_FLOAT ), - DEFINE_FIELD( CTripmineGrenade, m_hOwner, FIELD_EHANDLE ), - DEFINE_FIELD( CTripmineGrenade, m_pBeam, FIELD_CLASSPTR ), - DEFINE_FIELD( CTripmineGrenade, m_posOwner, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_angleOwner, FIELD_VECTOR ), - DEFINE_FIELD( CTripmineGrenade, m_pRealOwner, FIELD_EDICT ), -}; - -IMPLEMENT_SAVERESTORE(CTripmineGrenade,CGrenade); - - -void CTripmineGrenade :: Spawn( void ) -{ - Precache( ); - // motor - pev->movetype = MOVETYPE_FLY; - pev->solid = SOLID_NOT; - - SET_MODEL(ENT(pev), "models/v_tripmine.mdl"); - pev->frame = 0; - pev->body = 3; - pev->sequence = TRIPMINE_WORLD; - ResetSequenceInfo( ); - pev->framerate = 0; - - UTIL_SetSize(pev, Vector( -8, -8, -8), Vector(8, 8, 8)); - UTIL_SetOrigin( pev, pev->origin ); - - if (pev->spawnflags & 1) - { - // power up quickly - m_flPowerUp = gpGlobals->time + 1.0; - } - else - { - // power up in 2.5 seconds - m_flPowerUp = gpGlobals->time + 2.5; - } - - SetThink( &CTripmineGrenade::PowerupThink ); - pev->nextthink = gpGlobals->time + 0.2; - - pev->takedamage = DAMAGE_YES; - pev->dmg = gSkillData.plrDmgTripmine; - pev->health = 1; // don't let die normally - - if (pev->owner != NULL) - { - // play deploy sound - EMIT_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav", 1.0, ATTN_NORM ); - EMIT_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav", 0.2, ATTN_NORM ); // chargeup - - m_pRealOwner = pev->owner;// see CTripmineGrenade for why. - } - - UTIL_MakeAimVectors( pev->angles ); - - m_vecDir = gpGlobals->v_forward; - m_vecEnd = pev->origin + m_vecDir * 2048; -} - - -void CTripmineGrenade :: Precache( void ) -{ - PRECACHE_MODEL("models/v_tripmine.mdl"); - PRECACHE_SOUND("weapons/mine_deploy.wav"); - PRECACHE_SOUND("weapons/mine_activate.wav"); - PRECACHE_SOUND("weapons/mine_charge.wav"); -} - - -void CTripmineGrenade :: WarningThink( void ) -{ - // play warning sound - // EMIT_SOUND( ENT(pev), CHAN_VOICE, "buttons/Blip2.wav", 1.0, ATTN_NORM ); - - // set to power up - SetThink( &CTripmineGrenade::PowerupThink ); - pev->nextthink = gpGlobals->time + 1.0; -} - - -void CTripmineGrenade :: PowerupThink( void ) -{ - TraceResult tr; - - if (m_hOwner == 0) - { - // find an owner - edict_t *oldowner = pev->owner; - pev->owner = NULL; - UTIL_TraceLine( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 32, dont_ignore_monsters, ENT( pev ), &tr ); - if (tr.fStartSolid || (oldowner && tr.pHit == oldowner)) - { - pev->owner = oldowner; - m_flPowerUp += 0.1; - pev->nextthink = gpGlobals->time + 0.1; - return; - } - if (tr.flFraction < 1.0) - { - pev->owner = tr.pHit; - m_hOwner = CBaseEntity::Instance( pev->owner ); - m_posOwner = m_hOwner->pev->origin; - m_angleOwner = m_hOwner->pev->angles; - } - else - { - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); - STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); - SetThink(&CTripmineGrenade::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - ALERT( at_console, "WARNING:Tripmine at %.0f, %.0f, %.0f removed\n", pev->origin.x, pev->origin.y, pev->origin.z ); - KillBeam(); - return; - } - } - else if (m_posOwner != m_hOwner->pev->origin || m_angleOwner != m_hOwner->pev->angles) - { - // disable - STOP_SOUND( ENT(pev), CHAN_VOICE, "weapons/mine_deploy.wav" ); - STOP_SOUND( ENT(pev), CHAN_BODY, "weapons/mine_charge.wav" ); - CBaseEntity *pMine = Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - pMine->pev->spawnflags |= SF_NORESPAWN; - - SetThink( &CTripmineGrenade::SUB_Remove ); - KillBeam(); - pev->nextthink = gpGlobals->time + 0.1; - return; - } - // ALERT( at_console, "%d %.0f %.0f %0.f\n", pev->owner, m_pOwner->pev->origin.x, m_pOwner->pev->origin.y, m_pOwner->pev->origin.z ); - - if (gpGlobals->time > m_flPowerUp) - { - // make solid - pev->solid = SOLID_BBOX; - UTIL_SetOrigin( pev, pev->origin ); - - MakeBeam( ); - - // play enabled sound - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1, 75 ); - } - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CTripmineGrenade :: KillBeam( void ) -{ - if ( m_pBeam ) - { - UTIL_Remove( m_pBeam ); - m_pBeam = NULL; - } -} - - -void CTripmineGrenade :: MakeBeam( void ) -{ - TraceResult tr; - - // ALERT( at_console, "serverflags %f\n", gpGlobals->serverflags ); - - UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); - - m_flBeamLength = tr.flFraction; - - // set to follow laser spot - SetThink( &CTripmineGrenade::BeamBreakThink ); - pev->nextthink = gpGlobals->time + 0.1; - - Vector vecTmpEnd = pev->origin + m_vecDir * 2048 * m_flBeamLength; - - m_pBeam = CBeam::BeamCreate( g_pModelNameLaser, 10 ); - m_pBeam->PointEntInit( vecTmpEnd, entindex() ); - m_pBeam->SetColor( 0, 214, 198 ); - m_pBeam->SetScrollRate( 255 ); - m_pBeam->SetBrightness( 64 ); -} - - -void CTripmineGrenade :: BeamBreakThink( void ) -{ - BOOL bBlowup = 0; - - TraceResult tr; - - // HACKHACK Set simple box using this really nice global! - gpGlobals->trace_flags = FTRACE_SIMPLEBOX; - UTIL_TraceLine( pev->origin, m_vecEnd, dont_ignore_monsters, ENT( pev ), &tr ); - - // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength ); - - // respawn detect. - if ( !m_pBeam ) - { - MakeBeam( ); - if ( tr.pHit ) - m_hOwner = CBaseEntity::Instance( tr.pHit ); // reset owner too - } - - if (fabs( m_flBeamLength - tr.flFraction ) > 0.001) - { - bBlowup = 1; - } - else - { - if (m_hOwner == 0) - bBlowup = 1; - else if (m_posOwner != m_hOwner->pev->origin) - bBlowup = 1; - else if (m_angleOwner != m_hOwner->pev->angles) - bBlowup = 1; - } - - if (bBlowup) - { - // a bit of a hack, but all CGrenade code passes pev->owner along to make sure the proper player gets credit for the kill - // so we have to restore pev->owner from pRealOwner, because an entity's tracelines don't strike it's pev->owner which meant - // that a player couldn't trigger his own tripmine. Now that the mine is exploding, it's safe the restore the owner so the - // CGrenade code knows who the explosive really belongs to. - pev->owner = m_pRealOwner; - pev->health = 0; - Killed( VARS( pev->owner ), GIB_NORMAL ); - return; - } - - pev->nextthink = gpGlobals->time + 0.1; -} - -int CTripmineGrenade :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - if (gpGlobals->time < m_flPowerUp && flDamage < pev->health) - { - // disable - // Create( "weapon_tripmine", pev->origin + m_vecDir * 24, pev->angles ); - SetThink( &CTripmineGrenade::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; - KillBeam(); - return FALSE; - } - return CGrenade::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CTripmineGrenade::Killed( entvars_t *pevAttacker, int iGib ) -{ - pev->takedamage = DAMAGE_NO; - - if ( pevAttacker && ( pevAttacker->flags & FL_CLIENT ) ) - { - // some client has destroyed this mine, he'll get credit for any kills - pev->owner = ENT( pevAttacker ); - } - - SetThink( &CTripmineGrenade::DelayDeathThink ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.3 ); - - EMIT_SOUND( ENT(pev), CHAN_BODY, "common/null.wav", 0.5, ATTN_NORM ); // shut off chargeup -} - - -void CTripmineGrenade::DelayDeathThink( void ) -{ - KillBeam(); - TraceResult tr; - UTIL_TraceLine ( pev->origin + m_vecDir * 8, pev->origin - m_vecDir * 64, dont_ignore_monsters, ENT(pev), & tr); - - Explode( &tr, DMG_BLAST ); -} -#endif - -LINK_ENTITY_TO_CLASS( weapon_tripmine, CTripmine ); - -void CTripmine::Spawn( ) -{ - Precache( ); - m_iId = WEAPON_TRIPMINE; - SET_MODEL(ENT(pev), "models/v_tripmine.mdl"); - pev->frame = 0; - pev->body = 3; - pev->sequence = TRIPMINE_GROUND; - // ResetSequenceInfo( ); - pev->framerate = 0; - - FallInit();// get ready to fall down - - m_iDefaultAmmo = TRIPMINE_DEFAULT_GIVE; - -#ifdef CLIENT_DLL - if ( !bIsMultiplayer() ) -#else - if ( !g_pGameRules->IsDeathmatch() ) -#endif - { - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 28) ); - } -} - -void CTripmine::Precache( void ) -{ - PRECACHE_MODEL ("models/v_tripmine.mdl"); - PRECACHE_MODEL ("models/p_tripmine.mdl"); - UTIL_PrecacheOther( "monster_tripmine" ); - - m_usTripFire = PRECACHE_EVENT( 1, "events/tripfire.sc" ); -} - -int CTripmine::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "Trip Mine"; - p->iMaxAmmo1 = TRIPMINE_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = WEAPON_NOCLIP; - p->iSlot = 4; - p->iPosition = 2; - p->iId = m_iId = WEAPON_TRIPMINE; - p->iWeight = TRIPMINE_WEIGHT; - p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE; - - return 1; -} - -BOOL CTripmine::Deploy( ) -{ - //pev->body = 0; - return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); -} - - -void CTripmine::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - - if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) - { - // out of mines - m_pPlayer->pev->weapons &= ~(1<nextthink = gpGlobals->time + 0.1; - } - - SendWeaponAnim( TRIPMINE_HOLSTER ); - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); -} - -void CTripmine::PrimaryAttack( void ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return; - - UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming = gpGlobals->v_forward; - - TraceResult tr; - - UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); - - int flags; -#ifdef CLIENT_WEAPONS - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usTripFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - - if (tr.flFraction < 1.0) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - if ( pEntity && !(pEntity->pev->flags & FL_CONVEYOR) ) - { - Vector angles = UTIL_VecToAngles( tr.vecPlaneNormal ); - - CBaseEntity::Create( "monster_tripmine", tr.vecEndPos + tr.vecPlaneNormal * 8, angles, m_pPlayer->edict() ); - - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) - { - // no more mines! - RetireWeapon(); - return; - } - } - else - { - // ALERT( at_console, "no deploy\n" ); - } - } - else - { - - } - - m_flNextPrimaryAttack = GetNextAttackDelay(0.3); - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - -void CTripmine::WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) - { - SendWeaponAnim( TRIPMINE_DRAW ); - } - else - { - RetireWeapon(); - return; - } - - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); - if (flRand <= 0.25) - { - iAnim = TRIPMINE_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; - } - else if (flRand <= 0.75) - { - iAnim = TRIPMINE_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 30.0; - } - else - { - iAnim = TRIPMINE_FIDGET; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 100.0 / 30.0; - } - - SendWeaponAnim( iAnim ); -} - - - - diff --git a/sdk/dlls/turret.cpp b/sdk/dlls/turret.cpp deleted file mode 100644 index 9f90a09..0000000 --- a/sdk/dlls/turret.cpp +++ /dev/null @@ -1,1303 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -/* - -===== turret.cpp ======================================================== - -*/ - -// -// TODO: -// Take advantage of new monster fields like m_hEnemy and get rid of that OFFSET() stuff -// Revisit enemy validation stuff, maybe it's not necessary with the newest monster code -// - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "effects.h" - -extern Vector VecBModelOrigin( entvars_t* pevBModel ); - -#define TURRET_SHOTS 2 -#define TURRET_RANGE (100 * 12) -#define TURRET_SPREAD Vector( 0, 0, 0 ) -#define TURRET_TURNRATE 30 //angles per 0.1 second -#define TURRET_MAXWAIT 15 // seconds turret will stay active w/o a target -#define TURRET_MAXSPIN 5 // seconds turret barrel will spin w/o a target -#define TURRET_MACHINE_VOLUME 0.5 - -typedef enum -{ - TURRET_ANIM_NONE = 0, - TURRET_ANIM_FIRE, - TURRET_ANIM_SPIN, - TURRET_ANIM_DEPLOY, - TURRET_ANIM_RETIRE, - TURRET_ANIM_DIE, -} TURRET_ANIM; - -class CBaseTurret : public CBaseMonster -{ -public: - void Spawn(void); - virtual void Precache(void); - void KeyValue( KeyValueData *pkvd ); - void EXPORT TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - - virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); - virtual int Classify(void); - - int BloodColor( void ) { return DONT_BLEED; } - void GibMonster( void ) {} // UNDONE: Throw turret gibs? - - // Think functions - - void EXPORT ActiveThink(void); - void EXPORT SearchThink(void); - void EXPORT AutoSearchThink(void); - void EXPORT TurretDeath(void); - - virtual void EXPORT SpinDownCall(void) { m_iSpin = 0; } - virtual void EXPORT SpinUpCall(void) { m_iSpin = 1; } - - // void SpinDown(void); - // float EXPORT SpinDownCall( void ) { return SpinDown(); } - - // virtual float SpinDown(void) { return 0;} - // virtual float Retire(void) { return 0;} - - void EXPORT Deploy(void); - void EXPORT Retire(void); - - void EXPORT Initialize(void); - - virtual void Ping(void); - virtual void EyeOn(void); - virtual void EyeOff(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void SetTurretAnim(TURRET_ANIM anim); - int MoveTurret(void); - virtual void Shoot(Vector &vecSrc, Vector &vecDirToEnemy) { }; - - float m_flMaxSpin; // Max time to spin the barrel w/o a target - int m_iSpin; - - CSprite *m_pEyeGlow; - int m_eyeBrightness; - - int m_iDeployHeight; - int m_iRetractHeight; - int m_iMinPitch; - - int m_iBaseTurnRate; // angles per second - float m_fTurnRate; // actual turn rate - int m_iOrientation; // 0 = floor, 1 = Ceiling - int m_iOn; - int m_fBeserk; // Sometimes this bitch will just freak out - int m_iAutoStart; // true if the turret auto deploys when a target - // enters its range - - Vector m_vecLastSight; - float m_flLastSight; // Last time we saw a target - float m_flMaxWait; // Max time to seach w/o a target - int m_iSearchSpeed; // Not Used! - - // movement - float m_flStartYaw; - Vector m_vecCurAngles; - Vector m_vecGoalAngles; - - - float m_flPingTime; // Time until the next ping, used when searching - float m_flSpinUpTime; // Amount of time until the barrel should spin down when searching -}; - - -TYPEDESCRIPTION CBaseTurret::m_SaveData[] = -{ - DEFINE_FIELD( CBaseTurret, m_flMaxSpin, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSpin, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_pEyeGlow, FIELD_CLASSPTR ), - DEFINE_FIELD( CBaseTurret, m_eyeBrightness, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iDeployHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iRetractHeight, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iMinPitch, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_iBaseTurnRate, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fTurnRate, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iOrientation, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iOn, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_fBeserk, FIELD_INTEGER ), - DEFINE_FIELD( CBaseTurret, m_iAutoStart, FIELD_INTEGER ), - - - DEFINE_FIELD( CBaseTurret, m_vecLastSight, FIELD_POSITION_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_flLastSight, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flMaxWait, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_iSearchSpeed, FIELD_INTEGER ), - - DEFINE_FIELD( CBaseTurret, m_flStartYaw, FIELD_FLOAT ), - DEFINE_FIELD( CBaseTurret, m_vecCurAngles, FIELD_VECTOR ), - DEFINE_FIELD( CBaseTurret, m_vecGoalAngles, FIELD_VECTOR ), - - DEFINE_FIELD( CBaseTurret, m_flPingTime, FIELD_TIME ), - DEFINE_FIELD( CBaseTurret, m_flSpinUpTime, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CBaseTurret, CBaseMonster ); - -class CTurret : public CBaseTurret -{ -public: - void Spawn(void); - void Precache(void); - // Think functions - void SpinUpCall(void); - void SpinDownCall(void); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - - static TYPEDESCRIPTION m_SaveData[]; - - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - -private: - int m_iStartSpin; - -}; -TYPEDESCRIPTION CTurret::m_SaveData[] = -{ - DEFINE_FIELD( CTurret, m_iStartSpin, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CTurret, CBaseTurret ); - - -class CMiniTurret : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); -}; - - -LINK_ENTITY_TO_CLASS( monster_turret, CTurret ); -LINK_ENTITY_TO_CLASS( monster_miniturret, CMiniTurret ); - -void CBaseTurret::KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "maxsleep")) - { - m_flMaxWait = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "orientation")) - { - m_iOrientation = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "searchspeed")) - { - m_iSearchSpeed = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - - } - else if (FStrEq(pkvd->szKeyName, "turnrate")) - { - m_iBaseTurnRate = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if (FStrEq(pkvd->szKeyName, "style") || - FStrEq(pkvd->szKeyName, "height") || - FStrEq(pkvd->szKeyName, "value1") || - FStrEq(pkvd->szKeyName, "value2") || - FStrEq(pkvd->szKeyName, "value3")) - pkvd->fHandled = TRUE; - else - CBaseMonster::KeyValue( pkvd ); -} - - -void CBaseTurret::Spawn() -{ - Precache( ); - pev->nextthink = gpGlobals->time + 1; - pev->movetype = MOVETYPE_FLY; - pev->sequence = 0; - pev->frame = 0; - pev->solid = SOLID_SLIDEBOX; - pev->takedamage = DAMAGE_AIM; - - SetBits (pev->flags, FL_MONSTER); - SetUse( &CBaseTurret::TurretUse ); - - if (( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - && !( pev->spawnflags & SF_MONSTER_TURRET_STARTINACTIVE )) - { - m_iAutoStart = TRUE; - } - - ResetSequenceInfo( ); - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - m_flFieldOfView = VIEW_FIELD_FULL; - // m_flSightRange = TURRET_RANGE; -} - - -void CBaseTurret::Precache( ) -{ - PRECACHE_SOUND ("turret/tu_fire1.wav"); - PRECACHE_SOUND ("turret/tu_ping.wav"); - PRECACHE_SOUND ("turret/tu_active2.wav"); - PRECACHE_SOUND ("turret/tu_die.wav"); - PRECACHE_SOUND ("turret/tu_die2.wav"); - PRECACHE_SOUND ("turret/tu_die3.wav"); - // PRECACHE_SOUND ("turret/tu_retract.wav"); // just use deploy sound to save memory - PRECACHE_SOUND ("turret/tu_deploy.wav"); - PRECACHE_SOUND ("turret/tu_spinup.wav"); - PRECACHE_SOUND ("turret/tu_spindown.wav"); - PRECACHE_SOUND ("turret/tu_search.wav"); - PRECACHE_SOUND ("turret/tu_alert.wav"); -} - -#define TURRET_GLOW_SPRITE "sprites/flare3.spr" - -void CTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/turret.mdl"); - pev->health = gSkillData.turretHealth; - m_HackedGunPos = Vector( 0, 0, 12.75 ); - m_flMaxSpin = TURRET_MAXSPIN; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-32, -32, -m_iRetractHeight), Vector(32, 32, m_iRetractHeight)); - - SetThink(&CTurret::Initialize); - - m_pEyeGlow = CSprite::SpriteCreate( TURRET_GLOW_SPRITE, pev->origin, FALSE ); - m_pEyeGlow->SetTransparency( kRenderGlow, 255, 0, 0, 0, kRenderFxNoDissipation ); - m_pEyeGlow->SetAttachment( edict(), 2 ); - m_eyeBrightness = 0; - - pev->nextthink = gpGlobals->time + 0.3; -} - -void CTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/turret.mdl"); - PRECACHE_MODEL (TURRET_GLOW_SPRITE); -} - -void CMiniTurret::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/miniturret.mdl"); - pev->health = gSkillData.miniturretHealth; - m_HackedGunPos = Vector( 0, 0, 12.75 ); - m_flMaxSpin = 0; - pev->view_ofs.z = 12.75; - - CBaseTurret::Spawn( ); - m_iRetractHeight = 16; - m_iDeployHeight = 32; - m_iMinPitch = -15; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetThink(&CMiniTurret::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - - -void CMiniTurret::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/miniturret.mdl"); - PRECACHE_SOUND("weapons/hks1.wav"); - PRECACHE_SOUND("weapons/hks2.wav"); - PRECACHE_SOUND("weapons/hks3.wav"); -} - -void CBaseTurret::Initialize(void) -{ - m_iOn = 0; - m_fBeserk = 0; - m_iSpin = 0; - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - if (m_iBaseTurnRate == 0) m_iBaseTurnRate = TURRET_TURNRATE; - if (m_flMaxWait == 0) m_flMaxWait = TURRET_MAXWAIT; - m_flStartYaw = pev->angles.y; - if (m_iOrientation == 1) - { - pev->idealpitch = 180; - pev->angles.x = 180; - pev->view_ofs.z = -pev->view_ofs.z; - pev->effects |= EF_INVLIGHT; - pev->angles.y = pev->angles.y + 180; - if (pev->angles.y > 360) - pev->angles.y = pev->angles.y - 360; - } - - m_vecGoalAngles.x = 0; - - if (m_iAutoStart) - { - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); -} - -void CBaseTurret::TurretUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_iOn ) ) - return; - - if (m_iOn) - { - m_hEnemy = NULL; - pev->nextthink = gpGlobals->time + 0.1; - m_iAutoStart = FALSE;// switching off a turret disables autostart - //!!!! this should spin down first!!BUGBUG - SetThink(&CBaseTurret::Retire); - } - else - { - pev->nextthink = gpGlobals->time + 0.1; // turn on delay - - // if the turret is flagged as an autoactivate turret, re-enable it's ability open self. - if ( pev->spawnflags & SF_MONSTER_TURRET_AUTOACTIVATE ) - { - m_iAutoStart = TRUE; - } - - SetThink(&CBaseTurret::Deploy); - } -} - - -void CBaseTurret::Ping( void ) -{ - // make the pinging noise every second while searching - if (m_flPingTime == 0) - m_flPingTime = gpGlobals->time + 1; - else if (m_flPingTime <= gpGlobals->time) - { - m_flPingTime = gpGlobals->time + 1; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_ping.wav", 1, ATTN_NORM); - EyeOn( ); - } - else if (m_eyeBrightness > 0) - { - EyeOff( ); - } -} - - -void CBaseTurret::EyeOn( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness != 255) - { - m_eyeBrightness = 255; - } - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } -} - - -void CBaseTurret::EyeOff( ) -{ - if (m_pEyeGlow) - { - if (m_eyeBrightness > 0) - { - m_eyeBrightness = max( 0, m_eyeBrightness - 30 ); - m_pEyeGlow->SetBrightness( m_eyeBrightness ); - } - } -} - - -void CBaseTurret::ActiveThink(void) -{ - int fAttack = 0; - Vector vecDirToEnemy; - - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if ((!m_iOn) || (m_hEnemy == 0)) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - - // if it's dead, look for something new - if ( !m_hEnemy->IsAlive() ) - { - if (!m_flLastSight) - { - m_flLastSight = gpGlobals->time + 0.5; // continue-shooting timeout - } - else - { - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - } - - Vector vecMid = pev->origin + pev->view_ofs; - Vector vecMidEnemy = m_hEnemy->BodyTarget( vecMid ); - - // Look for our current enemy - int fEnemyVisible = FBoxVisible(pev, m_hEnemy->pev, vecMidEnemy ); - - vecDirToEnemy = vecMidEnemy - vecMid; // calculate dir and dist to enemy - float flDistToEnemy = vecDirToEnemy.Length(); - - Vector vec = UTIL_VecToAngles(vecMidEnemy - vecMid); - - // Current enmey is not visible. - if (!fEnemyVisible || (flDistToEnemy > TURRET_RANGE)) - { - if (!m_flLastSight) - m_flLastSight = gpGlobals->time + 0.5; - else - { - // Should we look for a new target? - if (gpGlobals->time > m_flLastSight) - { - m_hEnemy = NULL; - m_flLastSight = gpGlobals->time + m_flMaxWait; - SetThink(&CBaseTurret::SearchThink); - return; - } - } - fEnemyVisible = 0; - } - else - { - m_vecLastSight = vecMidEnemy; - } - - UTIL_MakeAimVectors(m_vecCurAngles); - - /* - ALERT( at_console, "%.0f %.0f : %.2f %.2f %.2f\n", - m_vecCurAngles.x, m_vecCurAngles.y, - gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_forward.z ); - */ - - Vector vecLOS = vecDirToEnemy; //vecMid - m_vecLastSight; - vecLOS = vecLOS.Normalize(); - - // Is the Gun looking at the target - if (DotProduct(vecLOS, gpGlobals->v_forward) <= 0.866) // 30 degree slop - fAttack = FALSE; - else - fAttack = TRUE; - - // fire the gun - if (m_iSpin && ((fAttack) || (m_fBeserk))) - { - Vector vecSrc, vecAng; - GetAttachment( 0, vecSrc, vecAng ); - SetTurretAnim(TURRET_ANIM_FIRE); - Shoot(vecSrc, gpGlobals->v_forward ); - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } - - //move the gun - if (m_fBeserk) - { - if (RANDOM_LONG(0,9) == 0) - { - m_vecGoalAngles.y = RANDOM_FLOAT(0,360); - m_vecGoalAngles.x = RANDOM_FLOAT(0,90) - 90 * m_iOrientation; - TakeDamage(pev,pev,1, DMG_GENERIC); // don't beserk forever - return; - } - } - else if (fEnemyVisible) - { - if (vec.y > 360) - vec.y -= 360; - - if (vec.y < 0) - vec.y += 360; - - //ALERT(at_console, "[%.2f]", vec.x); - - if (vec.x < -180) - vec.x += 360; - - if (vec.x > 180) - vec.x -= 360; - - // now all numbers should be in [1...360] - // pin to turret limitations to [-90...15] - - if (m_iOrientation == 0) - { - if (vec.x > 90) - vec.x = 90; - else if (vec.x < m_iMinPitch) - vec.x = m_iMinPitch; - } - else - { - if (vec.x < -90) - vec.x = -90; - else if (vec.x > -m_iMinPitch) - vec.x = -m_iMinPitch; - } - - // ALERT(at_console, "->[%.2f]\n", vec.x); - - m_vecGoalAngles.y = vec.y; - m_vecGoalAngles.x = vec.x; - - } - - SpinUpCall(); - MoveTurret(); -} - - -void CTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_12MM, 1 ); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "turret/tu_fire1.wav", 1, 0.6); - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CMiniTurret::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_9MM, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - - -void CBaseTurret::Deploy(void) -{ - pev->nextthink = gpGlobals->time + 0.1; - StudioFrameAdvance( ); - - if (pev->sequence != TURRET_ANIM_DEPLOY) - { - m_iOn = 1; - SetTurretAnim(TURRET_ANIM_DEPLOY); - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_deploy.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SUB_UseTargets( this, USE_ON, 0 ); - } - - if (m_fSequenceFinished) - { - pev->maxs.z = m_iDeployHeight; - pev->mins.z = -m_iDeployHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - - m_vecCurAngles.x = 0; - - if (m_iOrientation == 1) - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y + 180 ); - } - else - { - m_vecCurAngles.y = UTIL_AngleMod( pev->angles.y ); - } - - SetTurretAnim(TURRET_ANIM_SPIN); - pev->framerate = 0; - SetThink(&CBaseTurret::SearchThink); - } - - m_flLastSight = gpGlobals->time + m_flMaxWait; -} - -void CBaseTurret::Retire(void) -{ - // make the turret level - m_vecGoalAngles.x = 0; - m_vecGoalAngles.y = m_flStartYaw; - - pev->nextthink = gpGlobals->time + 0.1; - - StudioFrameAdvance( ); - - EyeOff( ); - - if (!MoveTurret()) - { - if (m_iSpin) - { - SpinDownCall(); - } - else if (pev->sequence != TURRET_ANIM_RETIRE) - { - SetTurretAnim(TURRET_ANIM_RETIRE); - EMIT_SOUND_DYN(ENT(pev), CHAN_BODY, "turret/tu_deploy.wav", TURRET_MACHINE_VOLUME, ATTN_NORM, 0, 120); - SUB_UseTargets( this, USE_OFF, 0 ); - } - else if (m_fSequenceFinished) - { - m_iOn = 0; - m_flLastSight = 0; - SetTurretAnim(TURRET_ANIM_NONE); - pev->maxs.z = m_iRetractHeight; - pev->mins.z = -m_iRetractHeight; - UTIL_SetSize(pev, pev->mins, pev->maxs); - if (m_iAutoStart) - { - SetThink(&CBaseTurret::AutoSearchThink); - pev->nextthink = gpGlobals->time + .1; - } - else - SetThink(&CBaseTurret::SUB_DoNothing); - } - } - else - { - SetTurretAnim(TURRET_ANIM_SPIN); - } -} - - -void CTurret::SpinUpCall(void) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - // Are we already spun up? If not start the two stage process. - if (!m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - // for the first pass, spin up the the barrel - if (!m_iStartSpin) - { - pev->nextthink = gpGlobals->time + 1.0; // spinup delay - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_spinup.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - m_iStartSpin = 1; - pev->framerate = 0.1; - } - // after the barrel is spun up, turn on the hum - else if (pev->framerate >= 1.0) - { - pev->nextthink = gpGlobals->time + 0.1; // retarget delay - EMIT_SOUND(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - SetThink(&CTurret::ActiveThink); - m_iStartSpin = 0; - m_iSpin = 1; - } - else - { - pev->framerate += 0.075; - } - } - - if (m_iSpin) - { - SetThink(&CTurret::ActiveThink); - } -} - - -void CTurret::SpinDownCall(void) -{ - if (m_iSpin) - { - SetTurretAnim( TURRET_ANIM_SPIN ); - if (pev->framerate == 1.0) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - EMIT_SOUND(ENT(pev), CHAN_ITEM, "turret/tu_spindown.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } - pev->framerate -= 0.02; - if (pev->framerate <= 0) - { - pev->framerate = 0; - m_iSpin = 0; - } - } -} - - -void CBaseTurret::SetTurretAnim(TURRET_ANIM anim) -{ - if (pev->sequence != anim) - { - switch(anim) - { - case TURRET_ANIM_FIRE: - case TURRET_ANIM_SPIN: - if (pev->sequence != TURRET_ANIM_FIRE && pev->sequence != TURRET_ANIM_SPIN) - { - pev->frame = 0; - } - break; - default: - pev->frame = 0; - break; - } - - pev->sequence = anim; - ResetSequenceInfo( ); - - switch(anim) - { - case TURRET_ANIM_RETIRE: - pev->frame = 255; - pev->framerate = -1.0; - break; - case TURRET_ANIM_DIE: - pev->framerate = 1.0; - break; - default: - break; - } - //ALERT(at_console, "Turret anim #%d\n", anim); - } -} - - -// -// This search function will sit with the turret deployed and look for a new target. -// After a set amount of time, the barrel will spin down. After m_flMaxWait, the turret will -// retact. -// -void CBaseTurret::SearchThink(void) -{ - // ensure rethink - SetTurretAnim(TURRET_ANIM_SPIN); - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (m_flSpinUpTime == 0 && m_flMaxSpin) - m_flSpinUpTime = gpGlobals->time + m_flMaxSpin; - - Ping( ); - - // If we have a target and we're still healthy - if (m_hEnemy != 0) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - - // Acquire Target - if (m_hEnemy == 0) - { - Look(TURRET_RANGE); - m_hEnemy = BestVisibleEnemy(); - } - - // If we've found a target, spin up the barrel and start to attack - if (m_hEnemy != 0) - { - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::ActiveThink); - } - else - { - // Are we out of time, do we need to retract? - if (gpGlobals->time > m_flLastSight) - { - //Before we retrace, make sure that we are spun down. - m_flLastSight = 0; - m_flSpinUpTime = 0; - SetThink(&CBaseTurret::Retire); - } - // should we stop the spin? - else if ((m_flSpinUpTime) && (gpGlobals->time > m_flSpinUpTime)) - { - SpinDownCall(); - } - - // generic hunt for new victims - m_vecGoalAngles.y = (m_vecGoalAngles.y + 0.1 * m_fTurnRate); - if (m_vecGoalAngles.y >= 360) - m_vecGoalAngles.y -= 360; - MoveTurret(); - } -} - - -// -// This think function will deploy the turret when something comes into range. This is for -// automatically activated turrets. -// -void CBaseTurret::AutoSearchThink(void) -{ - // ensure rethink - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.3; - - // If we have a target and we're still healthy - - if (m_hEnemy != 0) - { - if (!m_hEnemy->IsAlive() ) - m_hEnemy = NULL;// Dead enemy forces a search for new one - } - - // Acquire Target - - if (m_hEnemy == 0) - { - Look( TURRET_RANGE ); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != 0) - { - SetThink(&CBaseTurret::Deploy); - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_alert.wav", TURRET_MACHINE_VOLUME, ATTN_NORM); - } -} - - -void CBaseTurret :: TurretDeath( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - if (m_iOrientation == 0) - m_vecGoalAngles.x = -15; - else - m_vecGoalAngles.x = -90; - - SetTurretAnim(TURRET_ANIM_DIE); - - EyeOn( ); - } - - EyeOff( ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ) ); - WRITE_COORD( RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ) ); - WRITE_COORD( pev->origin.z - m_iOrientation * 64 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 25 ); // scale * 10 - WRITE_BYTE( 10 - m_iOrientation * 5); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 5 ) > gpGlobals->time) - { - Vector vecSrc = Vector( RANDOM_FLOAT( pev->absmin.x, pev->absmax.x ), RANDOM_FLOAT( pev->absmin.y, pev->absmax.y ), 0 ); - if (m_iOrientation == 0) - vecSrc = vecSrc + Vector( 0, 0, RANDOM_FLOAT( pev->origin.z, pev->absmax.z ) ); - else - vecSrc = vecSrc + Vector( 0, 0, RANDOM_FLOAT( pev->absmin.z, pev->origin.z ) ); - - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && !MoveTurret( ) && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - - - -void CBaseTurret :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - if ( ptr->iHitgroup == 10 ) - { - // hit armor - if ( pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0,10) < 1) ) - { - UTIL_Ricochet( ptr->vecEndPos, RANDOM_FLOAT( 1, 2) ); - pev->dmgtime = gpGlobals->time; - } - - flDamage = 0.1;// don't hurt the monster much, but allow bits_COND_LIGHT_DAMAGE to be generated - } - - if ( !pev->takedamage ) - return; - - AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType ); -} - -// take damage. bitsDamageType indicates type of damage sustained, ie: DMG_BULLET - -int CBaseTurret::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - flDamage /= 10.0; - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink(&CBaseTurret::TurretDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - if (pev->health <= 10) - { - if (m_iOn && (1 || RANDOM_LONG(0, 0x7FFF) > 800)) - { - m_fBeserk = 1; - SetThink(&CBaseTurret::SearchThink); - } - } - - return 1; -} - -int CBaseTurret::MoveTurret(void) -{ - int state = 0; - // any x movement? - - if (m_vecCurAngles.x != m_vecGoalAngles.x) - { - float flDir = m_vecGoalAngles.x > m_vecCurAngles.x ? 1 : -1 ; - - m_vecCurAngles.x += 0.1 * m_fTurnRate * flDir; - - // if we started below the goal, and now we're past, peg to goal - if (flDir == 1) - { - if (m_vecCurAngles.x > m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - else - { - if (m_vecCurAngles.x < m_vecGoalAngles.x) - m_vecCurAngles.x = m_vecGoalAngles.x; - } - - if (m_iOrientation == 0) - SetBoneController(1, -m_vecCurAngles.x); - else - SetBoneController(1, m_vecCurAngles.x); - state = 1; - } - - if (m_vecCurAngles.y != m_vecGoalAngles.y) - { - float flDir = m_vecGoalAngles.y > m_vecCurAngles.y ? 1 : -1 ; - float flDist = fabs(m_vecGoalAngles.y - m_vecCurAngles.y); - - if (flDist > 180) - { - flDist = 360 - flDist; - flDir = -flDir; - } - if (flDist > 30) - { - if (m_fTurnRate < m_iBaseTurnRate * 10) - { - m_fTurnRate += m_iBaseTurnRate; - } - } - else if (m_fTurnRate > 45) - { - m_fTurnRate -= m_iBaseTurnRate; - } - else - { - m_fTurnRate += m_iBaseTurnRate; - } - - m_vecCurAngles.y += 0.1 * m_fTurnRate * flDir; - - if (m_vecCurAngles.y < 0) - m_vecCurAngles.y += 360; - else if (m_vecCurAngles.y >= 360) - m_vecCurAngles.y -= 360; - - if (flDist < (0.05 * m_iBaseTurnRate)) - m_vecCurAngles.y = m_vecGoalAngles.y; - - //ALERT(at_console, "%.2f -> %.2f\n", m_vecCurAngles.y, y); - if (m_iOrientation == 0) - SetBoneController(0, m_vecCurAngles.y - pev->angles.y ); - else - SetBoneController(0, pev->angles.y - 180 - m_vecCurAngles.y ); - state = 1; - } - - if (!state) - m_fTurnRate = m_iBaseTurnRate; - - //ALERT(at_console, "(%.2f, %.2f)->(%.2f, %.2f)\n", m_vecCurAngles.x, - // m_vecCurAngles.y, m_vecGoalAngles.x, m_vecGoalAngles.y); - return state; -} - -// -// ID as a machine -// -int CBaseTurret::Classify ( void ) -{ - if (m_iOn || m_iAutoStart) - return CLASS_MACHINE; - return CLASS_NONE; -} - - - - -//========================================================= -// Sentry gun - smallest turret, placed near grunt entrenchments -//========================================================= -class CSentry : public CBaseTurret -{ -public: - void Spawn( ); - void Precache(void); - // other functions - void Shoot(Vector &vecSrc, Vector &vecDirToEnemy); - int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - void EXPORT SentryTouch( CBaseEntity *pOther ); - void EXPORT SentryDeath( void ); - -}; - -LINK_ENTITY_TO_CLASS( monster_sentry, CSentry ); - -void CSentry::Precache() -{ - CBaseTurret::Precache( ); - PRECACHE_MODEL ("models/sentry.mdl"); -} - -void CSentry::Spawn() -{ - Precache( ); - SET_MODEL(ENT(pev), "models/sentry.mdl"); - pev->health = gSkillData.sentryHealth; - m_HackedGunPos = Vector( 0, 0, 48 ); - pev->view_ofs.z = 48; - m_flMaxWait = 1E6; - m_flMaxSpin = 1E6; - - CBaseTurret::Spawn(); - m_iRetractHeight = 64; - m_iDeployHeight = 64; - m_iMinPitch = -60; - UTIL_SetSize(pev, Vector(-16, -16, -m_iRetractHeight), Vector(16, 16, m_iRetractHeight)); - - SetTouch(&CSentry::SentryTouch); - SetThink(&CSentry::Initialize); - pev->nextthink = gpGlobals->time + 0.3; -} - -void CSentry::Shoot(Vector &vecSrc, Vector &vecDirToEnemy) -{ - FireBullets( 1, vecSrc, vecDirToEnemy, TURRET_SPREAD, TURRET_RANGE, BULLET_MONSTER_MP5, 1 ); - - switch(RANDOM_LONG(0,2)) - { - case 0: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks1.wav", 1, ATTN_NORM); break; - case 1: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks2.wav", 1, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/hks3.wav", 1, ATTN_NORM); break; - } - pev->effects = pev->effects | EF_MUZZLEFLASH; -} - -int CSentry::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - if ( !pev->takedamage ) - return 0; - - if (!m_iOn) - { - SetThink( &CSentry::Deploy ); - SetUse( NULL ); - pev->nextthink = gpGlobals->time + 0.1; - } - - pev->health -= flDamage; - if (pev->health <= 0) - { - pev->health = 0; - pev->takedamage = DAMAGE_NO; - pev->dmgtime = gpGlobals->time; - - ClearBits (pev->flags, FL_MONSTER); // why are they set in the first place??? - - SetUse(NULL); - SetThink( &CSentry::SentryDeath); - SUB_UseTargets( this, USE_ON, 0 ); // wake up others - pev->nextthink = gpGlobals->time + 0.1; - - return 0; - } - - return 1; -} - - -void CSentry::SentryTouch( CBaseEntity *pOther ) -{ - if ( pOther && (pOther->IsPlayer() || (pOther->pev->flags & FL_MONSTER)) ) - { - TakeDamage(pOther->pev, pOther->pev, 0, 0 ); - } -} - - -void CSentry :: SentryDeath( void ) -{ - StudioFrameAdvance( ); - pev->nextthink = gpGlobals->time + 0.1; - - if (pev->deadflag != DEAD_DEAD) - { - pev->deadflag = DEAD_DEAD; - - float flRndSound = RANDOM_FLOAT ( 0 , 1 ); - - if ( flRndSound <= 0.33 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die.wav", 1.0, ATTN_NORM); - else if ( flRndSound <= 0.66 ) - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die2.wav", 1.0, ATTN_NORM); - else - EMIT_SOUND(ENT(pev), CHAN_BODY, "turret/tu_die3.wav", 1.0, ATTN_NORM); - - EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "turret/tu_active2.wav", 0, 0, SND_STOP, 100); - - SetBoneController( 0, 0 ); - SetBoneController( 1, 0 ); - - SetTurretAnim(TURRET_ANIM_DIE); - - pev->solid = SOLID_NOT; - pev->angles.y = UTIL_AngleMod( pev->angles.y + RANDOM_LONG( 0, 2 ) * 120 ); - - EyeOn( ); - } - - EyeOff( ); - - Vector vecSrc, vecAng; - GetAttachment( 1, vecSrc, vecAng ); - - if (pev->dmgtime + RANDOM_FLOAT( 0, 2 ) > gpGlobals->time) - { - // lots of smoke - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_SMOKE ); - WRITE_COORD( vecSrc.x + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.y + RANDOM_FLOAT( -16, 16 ) ); - WRITE_COORD( vecSrc.z - 32 ); - WRITE_SHORT( g_sModelIndexSmoke ); - WRITE_BYTE( 15 ); // scale * 10 - WRITE_BYTE( 8 ); // framerate - MESSAGE_END(); - } - - if (pev->dmgtime + RANDOM_FLOAT( 0, 8 ) > gpGlobals->time) - { - UTIL_Sparks( vecSrc ); - } - - if (m_fSequenceFinished && pev->dmgtime + 5 < gpGlobals->time) - { - pev->framerate = 0; - SetThink( NULL ); - } -} - diff --git a/sdk/dlls/util.cpp b/sdk/dlls/util.cpp deleted file mode 100644 index 6c01d84..0000000 --- a/sdk/dlls/util.cpp +++ /dev/null @@ -1,2551 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== util.cpp ======================================================== - - Utility code. Really not optional after all. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "saverestore.h" -#include -#include "shake.h" -#include "decals.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" - -float UTIL_WeaponTimeBase( void ) -{ -#if defined( CLIENT_WEAPONS ) - return 0.0; -#else - return gpGlobals->time; -#endif -} - -static unsigned int glSeed = 0; - -unsigned int seed_table[ 256 ] = -{ - 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, - 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, - 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, - 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, - 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, - 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, - 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, - 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, - 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, - 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, - 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, - 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, - 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, - 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, - 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, - 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 -}; - -unsigned int U_Random( void ) -{ - glSeed *= 69069; - glSeed += seed_table[ glSeed & 0xff ]; - - return ( ++glSeed & 0x0fffffff ); -} - -void U_Srand( unsigned int seed ) -{ - glSeed = seed_table[ seed & 0xff ]; -} - -/* -===================== -UTIL_SharedRandomLong -===================== -*/ -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) -{ - unsigned int range; - - U_Srand( (int)seed + low + high ); - - range = high - low + 1; - if ( !(range - 1) ) - { - return low; - } - else - { - int offset; - int rnum; - - rnum = U_Random(); - - offset = rnum % range; - - return (low + offset); - } -} - -/* -===================== -UTIL_SharedRandomFloat -===================== -*/ -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) -{ - // - unsigned int range; - - U_Srand( (int)seed + *(int *)&low + *(int *)&high ); - - U_Random(); - U_Random(); - - range = static_cast(high - low); - if ( !range ) - { - return low; - } - else - { - int tensixrand; - float offset; - - tensixrand = U_Random() & 65535; - - offset = (float)tensixrand / 65536.0; - - return (low + offset * range ); - } -} - -void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner ) -{ - pev->startpos = vecOrigin; - // Trace out line to end pos - TraceResult tr; - UTIL_MakeVectors( vecAngles ); - UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); - pev->endpos = tr.vecEndPos; - - // Now compute how long it will take based on current velocity - Vector vecTravel = pev->endpos - pev->startpos; - float travelTime = 0.0; - if ( pev->velocity.Length() > 0 ) - { - travelTime = vecTravel.Length() / pev->velocity.Length(); - } - pev->starttime = gpGlobals->time; - pev->impacttime = gpGlobals->time + travelTime; -} - -int g_groupmask = 0; -int g_groupop = 0; - -// Normal overrides -void UTIL_SetGroupTrace( int groupmask, int op ) -{ - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -void UTIL_UnsetGroupTrace( void ) -{ - g_groupmask = 0; - g_groupop = 0; - - ENGINE_SETGROUPMASK( 0, 0 ); -} - -// Smart version, it'll clean itself up when it pops off stack -UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op ) -{ - m_oldgroupmask = g_groupmask; - m_oldgroupop = g_groupop; - - g_groupmask = groupmask; - g_groupop = op; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -UTIL_GroupTrace::~UTIL_GroupTrace( void ) -{ - g_groupmask = m_oldgroupmask; - g_groupop = m_oldgroupop; - - ENGINE_SETGROUPMASK( g_groupmask, g_groupop ); -} - -TYPEDESCRIPTION gEntvarsDescription[] = -{ - DEFINE_ENTITY_FIELD( classname, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ), - DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ), - DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ), - - DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ), - DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ), - - DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ), - DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ), - DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ), - DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ), - - DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ), - - DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ), - - DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ), - DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ), - DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ), - - // Having these fields be local to the individual levels makes it easier to test those levels individually. - DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ), - DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( netname, FIELD_STRING ), - DEFINE_ENTITY_FIELD( message, FIELD_STRING ), - - DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ), - - DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ), - DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ), - DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ), - DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ), -}; - -#define ENTVARS_COUNT (sizeof(gEntvarsDescription)/sizeof(gEntvarsDescription[0])) - - -#ifdef DEBUG -edict_t *DBG_EntOfVars( const entvars_t *pev ) -{ - if (pev->pContainingEntity != NULL) - return pev->pContainingEntity; - ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); - edict_t* pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); - if (pent == NULL) - ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); - ((entvars_t *)pev)->pContainingEntity = pent; - return pent; -} -#endif //DEBUG - - -#ifdef DEBUG - void -DBG_AssertFunction( - BOOL fExpr, - const char* szExpr, - const char* szFile, - int szLine, - const char* szMessage) - { - if (fExpr) - return; - char szOut[512]; - if (szMessage != NULL) - sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); - else - sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine); - ALERT(at_console, szOut); - } -#endif // DEBUG - -BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) -{ - return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon ); -} - -// ripped this out of the engine -float UTIL_AngleMod(float a) -{ - if (a < 0) - { - a = a + 360 * ((int)(a / 360) + 1); - } - else if (a >= 360) - { - a = a - 360 * ((int)(a / 360)); - } - // a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - -float UTIL_AngleDiff( float destAngle, float srcAngle ) -{ - float delta; - - delta = destAngle - srcAngle; - if ( destAngle > srcAngle ) - { - if ( delta >= 180 ) - delta -= 360; - } - else - { - if ( delta <= -180 ) - delta += 360; - } - return delta; -} - -Vector UTIL_VecToAngles( const Vector &vec ) -{ - float rgflVecOut[3]; - VEC_TO_ANGLES(vec, rgflVecOut); - return Vector(rgflVecOut); -} - -// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType ) -void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType ) -{ - float rgfl[3]; - vecGoal.CopyToArray(rgfl); -// return MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); - MOVE_TO_ORIGIN ( pent, rgfl, flDist, iMoveType ); -} - - -int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - - count = 0; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( flagMask && !(pEdict->v.flags & flagMask) ) // Does it meet the criteria? - continue; - - if ( mins.x > pEdict->v.absmax.x || - mins.y > pEdict->v.absmax.y || - mins.z > pEdict->v.absmax.z || - maxs.x < pEdict->v.absmin.x || - maxs.y < pEdict->v.absmin.y || - maxs.z < pEdict->v.absmin.z ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - return count; -} - - -int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ) -{ - edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); - CBaseEntity *pEntity; - int count; - float distance, delta; - - count = 0; - float radiusSquared = radius * radius; - - if ( !pEdict ) - return count; - - for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) - { - if ( pEdict->free ) // Not in use - continue; - - if ( !(pEdict->v.flags & (FL_CLIENT|FL_MONSTER)) ) // Not a client/monster ? - continue; - - // Use origin for X & Y since they are centered for all monsters - // Now X - delta = center.x - pEdict->v.origin.x;//(pEdict->v.absmin.x + pEdict->v.absmax.x)*0.5; - delta *= delta; - - if ( delta > radiusSquared ) - continue; - distance = delta; - - // Now Y - delta = center.y - pEdict->v.origin.y;//(pEdict->v.absmin.y + pEdict->v.absmax.y)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - // Now Z - delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z)*0.5; - delta *= delta; - - distance += delta; - if ( distance > radiusSquared ) - continue; - - pEntity = CBaseEntity::Instance(pEdict); - if ( !pEntity ) - continue; - - pList[ count ] = pEntity; - count++; - - if ( count >= listMax ) - return count; - } - - - return count; -} - - -CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - - -CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ) -{ - edict_t *pentEntity; - - if (pStartEntity) - pentEntity = pStartEntity->edict(); - else - pentEntity = NULL; - - pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue ); - - if (!FNullEnt(pentEntity)) - return CBaseEntity::Instance(pentEntity); - return NULL; -} - -CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "classname", szName ); -} - -CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName ) -{ - return UTIL_FindEntityByString( pStartEntity, "targetname", szName ); -} - - -CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius ) -{ - CBaseEntity *pEntity = NULL; - - pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever ); - if (pEntity) - return pEntity; - - CBaseEntity *pSearch = NULL; - float flMaxDist2 = flRadius * flRadius; - while ((pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever )) != NULL) - { - float flDist2 = (pSearch->pev->origin - vecSrc).Length(); - flDist2 = flDist2 * flDist2; - if (flMaxDist2 > flDist2) - { - pEntity = pSearch; - flMaxDist2 = flDist2; - } - } - return pEntity; -} - - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) -{ - CBaseEntity *pPlayer = NULL; - - if ( playerIndex > 0 && playerIndex <= gpGlobals->maxClients ) - { - edict_t *pPlayerEdict = INDEXENT( playerIndex ); - if ( pPlayerEdict && !pPlayerEdict->free ) - { - pPlayer = CBaseEntity::Instance( pPlayerEdict ); - } - } - - return pPlayer; -} - - -void UTIL_MakeVectors( const Vector &vecAngles ) -{ - MAKE_VECTORS( vecAngles ); -} - - -void UTIL_MakeAimVectors( const Vector &vecAngles ) -{ - float rgflVec[3]; - vecAngles.CopyToArray(rgflVec); - rgflVec[0] = -rgflVec[0]; - MAKE_VECTORS(rgflVec); -} - - -#define SWAP(a,b,temp) ((temp)=(a),(a)=(b),(b)=(temp)) - -void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv ) -{ - MAKE_VECTORS(vec); - - float tmp; - pgv->v_right = pgv->v_right * -1; - - SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); - SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); - SWAP(pgv->v_right.z, pgv->v_up.y, tmp); -} - - -void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ) -{ - float rgfl[3]; - vecOrigin.CopyToArray(rgfl); - - if (samp && *samp == '!') - { - char name[32]; - if (SENTENCEG_Lookup(samp, name) >= 0) - EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); - } - else - EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); -} - -static unsigned short FixedUnsigned16( float value, float scale ) -{ - int output; - - output = static_cast(value * scale); - if ( output < 0 ) - output = 0; - if ( output > 0xFFFF ) - output = 0xFFFF; - - return (unsigned short)output; -} - -static short FixedSigned16( float value, float scale ) -{ - int output; - - output = static_cast(value * scale); - - if ( output > 32767 ) - output = 32767; - - if ( output < -32768 ) - output = -32768; - - return (short)output; -} - -// Shake the screen of all clients within radius -// radius == 0, shake all clients -// UNDONE: Allow caller to shake clients not ONGROUND? -// UNDONE: Fix falloff model (disabled)? -// UNDONE: Affect user controls? -void UTIL_ScreenShake( const Vector ¢er, float amplitude, float frequency, float duration, float radius ) -{ - int i; - float localAmplitude; - ScreenShake shake; - - shake.duration = FixedUnsigned16( duration, 1<<12 ); // 4.12 fixed - shake.frequency = FixedUnsigned16( frequency, 1<<8 ); // 8.8 fixed - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - if ( !pPlayer || !(pPlayer->pev->flags & FL_ONGROUND) ) // Don't shake if not onground - continue; - - localAmplitude = 0; - - if ( radius <= 0 ) - localAmplitude = amplitude; - else - { - Vector delta = center - pPlayer->pev->origin; - float distance = delta.Length(); - - // Had to get rid of this falloff - it didn't work well - if ( distance < radius ) - localAmplitude = amplitude;//radius - distance; - } - if ( localAmplitude ) - { - shake.amplitude = FixedUnsigned16( localAmplitude, 1<<12 ); // 4.12 fixed - - MESSAGE_BEGIN( MSG_ONE, gmsgShake, NULL, pPlayer->edict() ); // use the magic #1 for "one client" - - WRITE_SHORT( shake.amplitude ); // shake amount - WRITE_SHORT( shake.duration ); // shake lasts this long - WRITE_SHORT( shake.frequency ); // shake noise frequency - - MESSAGE_END(); - } - } -} - - - -void UTIL_ScreenShakeAll( const Vector ¢er, float amplitude, float frequency, float duration ) -{ - UTIL_ScreenShake( center, amplitude, frequency, duration, 0 ); -} - - -void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - fade.duration = FixedUnsigned16( fadeTime, 1<<12 ); // 4.12 fixed - fade.holdTime = FixedUnsigned16( fadeHold, 1<<12 ); // 4.12 fixed - fade.r = (int)color.x; - fade.g = (int)color.y; - fade.b = (int)color.z; - fade.a = alpha; - fade.fadeFlags = flags; -} - - -void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsgFade, NULL, pEntity->edict() ); // use the magic #1 for "one client" - - WRITE_SHORT( fade.duration ); // fade lasts this long - WRITE_SHORT( fade.holdTime ); // fade lasts this long - WRITE_SHORT( fade.fadeFlags ); // fade type (in / out) - WRITE_BYTE( fade.r ); // fade red - WRITE_BYTE( fade.g ); // fade green - WRITE_BYTE( fade.b ); // fade blue - WRITE_BYTE( fade.a ); // fade blue - - MESSAGE_END(); -} - - -void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - int i; - ScreenFade fade; - - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - - UTIL_ScreenFadeWrite( fade, pPlayer ); - } -} - - -void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ) -{ - ScreenFade fade; - - UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags ); - UTIL_ScreenFadeWrite( fade, pEntity ); -} - - -void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict() ); - WRITE_BYTE( TE_TEXTMESSAGE ); - WRITE_BYTE( textparms.channel & 0xFF ); - - WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); - WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); - WRITE_BYTE( textparms.effect ); - - WRITE_BYTE( textparms.r1 ); - WRITE_BYTE( textparms.g1 ); - WRITE_BYTE( textparms.b1 ); - WRITE_BYTE( textparms.a1 ); - - WRITE_BYTE( textparms.r2 ); - WRITE_BYTE( textparms.g2 ); - WRITE_BYTE( textparms.b2 ); - WRITE_BYTE( textparms.a2 ); - - WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); - - if ( textparms.effect == 2 ) - WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1<<8 ) ); - - if ( strlen( pMessage ) < 512 ) - { - WRITE_STRING( pMessage ); - } - else - { - char tmp[512]; - strncpy( tmp, pMessage, 511 ); - tmp[511] = 0; - WRITE_STRING( tmp ); - } - MESSAGE_END(); -} - -void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ) -{ - int i; - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_HudMessage( pPlayer, textparms, pMessage ); - } -} - - -extern int gmsgTextMsg, gmsgSayText; -void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg ); - WRITE_BYTE( msg_dest ); - WRITE_STRING( msg_name ); - - if ( param1 ) - WRITE_STRING( param1 ); - if ( param2 ) - WRITE_STRING( param2 ); - if ( param3 ) - WRITE_STRING( param3 ); - if ( param4 ) - WRITE_STRING( param4 ); - - MESSAGE_END(); -} - -void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) -{ - MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client ); - WRITE_BYTE( msg_dest ); - WRITE_STRING( msg_name ); - - if ( param1 ) - WRITE_STRING( param1 ); - if ( param2 ) - WRITE_STRING( param2 ); - if ( param3 ) - WRITE_STRING( param3 ); - if ( param4 ) - WRITE_STRING( param4 ); - - MESSAGE_END(); -} - -void UTIL_SayText( const char *pText, CBaseEntity *pEntity ) -{ - if ( !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pEntity->edict() ); - WRITE_BYTE( pEntity->entindex() ); - WRITE_STRING( pText ); - MESSAGE_END(); -} - -void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ) -{ - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( pEntity->entindex() ); - WRITE_STRING( pText ); - MESSAGE_END(); -} - - -char *UTIL_dtos1( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos2( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos3( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -char *UTIL_dtos4( int d ) -{ - static char buf[8]; - sprintf( buf, "%d", d ); - return buf; -} - -void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity ) -{ - if ( !pEntity || !pEntity->IsNetClient() ) - return; - - MESSAGE_BEGIN( MSG_ONE, gmsgHudText, NULL, pEntity->edict() ); - WRITE_STRING( pString ); - MESSAGE_END(); -} - - -void UTIL_ShowMessageAll( const char *pString ) -{ - int i; - - // loop through all players - - for ( i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBaseEntity *pPlayer = UTIL_PlayerByIndex( i ); - if ( pPlayer ) - UTIL_ShowMessage( pString, pPlayer ); - } -} - -// Overloaded to add IGNORE_GLASS -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass?0x100:0), pentIgnore, ptr ); -} - - -void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_LINE( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr ); -} - - -void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr ) -{ - TRACE_HULL( vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr ); -} - -void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr ) -{ - g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr ); -} - - -TraceResult UTIL_GetGlobalTrace( ) -{ - TraceResult tr; - - tr.fAllSolid = static_cast(gpGlobals->trace_allsolid); - tr.fStartSolid = static_cast(gpGlobals->trace_startsolid); - tr.fInOpen = static_cast(gpGlobals->trace_inopen); - tr.fInWater = static_cast(gpGlobals->trace_inwater); - tr.flFraction = gpGlobals->trace_fraction; - tr.flPlaneDist = gpGlobals->trace_plane_dist; - tr.pHit = gpGlobals->trace_ent; - tr.vecEndPos = gpGlobals->trace_endpos; - tr.vecPlaneNormal = gpGlobals->trace_plane_normal; - tr.iHitgroup = gpGlobals->trace_hitgroup; - return tr; -} - - -void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ) -{ - SET_SIZE( ENT(pev), vecMin, vecMax ); -} - - -float UTIL_VecToYaw( const Vector &vec ) -{ - return VEC_TO_YAW(vec); -} - - -void UTIL_SetOrigin( entvars_t *pev, const Vector &vecOrigin ) -{ - edict_t *ent = ENT(pev); - if ( ent ) - SET_ORIGIN( ent, vecOrigin ); -} - -void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ) -{ - PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount ); -} - - -float UTIL_Approach( float target, float value, float speed ) -{ - float delta = target - value; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_ApproachAngle( float target, float value, float speed ) -{ - target = UTIL_AngleMod( target ); - value = UTIL_AngleMod( target ); - - float delta = target - value; - - // Speed is assumed to be positive - if ( speed < 0 ) - speed = -speed; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - if ( delta > speed ) - value += speed; - else if ( delta < -speed ) - value -= speed; - else - value = target; - - return value; -} - - -float UTIL_AngleDistance( float next, float cur ) -{ - float delta = next - cur; - - if ( delta < -180 ) - delta += 360; - else if ( delta > 180 ) - delta -= 360; - - return delta; -} - - -float UTIL_SplineFraction( float value, float scale ) -{ - value = scale * value; - float valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - - -char* UTIL_VarArgs( const char *format, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start (argptr, format); - vsprintf (string, format,argptr); - va_end (argptr); - - return string; -} - -Vector UTIL_GetAimVector( edict_t *pent, float flSpeed ) -{ - Vector tmp; - GET_AIM_VECTOR(pent, flSpeed, tmp); - return tmp; -} - -int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) -{ - if (sMaster) - { - edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); - - if ( !FNullEnt(pentTarget) ) - { - CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); - if ( pMaster && (pMaster->ObjectCaps() & FCAP_MASTER) ) - return pMaster->IsTriggered( pActivator ); - } - - ALERT(at_console, "Master was null or not a master!\n"); - } - - // if this isn't a master entity, just say yes. - return 1; -} - -BOOL UTIL_ShouldShowBlood( int color ) -{ - if ( color != DONT_BLEED ) - { - if ( color == BLOOD_COLOR_RED ) - { - if ( CVAR_GET_FLOAT("violence_hblood") != 0 ) - return TRUE; - } - else - { - if ( CVAR_GET_FLOAT("violence_ablood") != 0 ) - return TRUE; - } - } - return FALSE; -} - -int UTIL_PointContents( const Vector &vec ) -{ - return POINT_CONTENTS(vec); -} - -void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSTREAM ); - WRITE_COORD( origin.x ); - WRITE_COORD( origin.y ); - WRITE_COORD( origin.z ); - WRITE_COORD( direction.x ); - WRITE_COORD( direction.y ); - WRITE_COORD( direction.z ); - WRITE_BYTE( color ); - WRITE_BYTE( min( amount, 255 ) ); - MESSAGE_END(); -} - -void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) -{ - if ( !UTIL_ShouldShowBlood( color ) ) - return; - - if ( color == DONT_BLEED || amount == 0 ) - return; - - if ( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED ) - color = 0; - - if ( g_pGameRules->IsMultiplayer() ) - { - // scale up blood effect in multiplayer for better visibility - amount *= 2; - } - - if ( amount > 255 ) - amount = 255; - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin ); - WRITE_BYTE( TE_BLOODSPRITE ); - WRITE_COORD( origin.x); // pos - WRITE_COORD( origin.y); - WRITE_COORD( origin.z); - WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model - WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models - WRITE_BYTE( color ); // color index into host_basepal - WRITE_BYTE( min( max( 3, amount / 10 ), 16 ) ); // size - MESSAGE_END(); -} - -Vector UTIL_RandomBloodVector( void ) -{ - Vector direction; - - direction.x = RANDOM_FLOAT ( -1, 1 ); - direction.y = RANDOM_FLOAT ( -1, 1 ); - direction.z = RANDOM_FLOAT ( 0, 1 ); - - return direction; -} - - -void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ) -{ - if ( UTIL_ShouldShowBlood( bloodColor ) ) - { - if ( bloodColor == BLOOD_COLOR_RED ) - UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG(0,5) ); - else - UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0,5) ); - } -} - - -void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) -{ - short entityIndex; - int index; - int message; - - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - // Only decal BSP models - if ( pTrace->pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit ); - if ( pEntity && !pEntity->IsBSPModel() ) - return; - entityIndex = ENTINDEX( pTrace->pHit ); - } - else - entityIndex = 0; - - message = TE_DECAL; - if ( entityIndex != 0 ) - { - if ( index > 255 ) - { - message = TE_DECALHIGH; - index -= 256; - } - } - else - { - message = TE_WORLDDECAL; - if ( index > 255 ) - { - message = TE_WORLDDECALHIGH; - index -= 256; - } - } - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( message ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_BYTE( index ); - if ( entityIndex ) - WRITE_SHORT( entityIndex ); - MESSAGE_END(); -} - -/* -============== -UTIL_PlayerDecalTrace - -A player is trying to apply his custom decal for the spray can. -Tell connected clients to display it, or use the default spray can decal -if the custom can't be loaded. -============== -*/ -void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ) -{ - int index; - - if (!bIsCustom) - { - if ( decalNumber < 0 ) - return; - - index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - } - else - index = decalNumber; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_PLAYERDECAL ); - WRITE_BYTE ( playernum ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - -void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) -{ - if ( decalNumber < 0 ) - return; - - int index = gDecals[ decalNumber ].index; - if ( index < 0 ) - return; - - if (pTrace->flFraction == 1.0) - return; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos ); - WRITE_BYTE( TE_GUNSHOTDECAL ); - WRITE_COORD( pTrace->vecEndPos.x ); - WRITE_COORD( pTrace->vecEndPos.y ); - WRITE_COORD( pTrace->vecEndPos.z ); - WRITE_SHORT( (short)ENTINDEX(pTrace->pHit) ); - WRITE_BYTE( index ); - MESSAGE_END(); -} - - -void UTIL_Sparks( const Vector &position ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_SPARKS ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - MESSAGE_END(); -} - - -void UTIL_Ricochet( const Vector &position, float scale ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position ); - WRITE_BYTE( TE_ARMOR_RICOCHET ); - WRITE_COORD( position.x ); - WRITE_COORD( position.y ); - WRITE_COORD( position.z ); - WRITE_BYTE( (int)(scale*10) ); - MESSAGE_END(); -} - - -BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ) -{ - // Everyone matches unless it's teamplay - if ( !g_pGameRules->IsTeamplay() ) - return TRUE; - - // Both on a team? - if ( *pTeamName1 != 0 && *pTeamName2 != 0 ) - { - if ( !stricmp( pTeamName1, pTeamName2 ) ) // Same Team? - return TRUE; - } - - return FALSE; -} - - -void UTIL_StringToVector( float *pVector, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c - { - pVector[j] = atof( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - if (j < 2) - { - /* - ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n", - pkvd->szClassName, pkvd->szKeyName, pkvd->szValue ); - */ - for (j = j+1;j < 3; j++) - pVector[j] = 0; - } -} - - -void UTIL_StringToIntArray( int *pVector, int count, const char *pString ) -{ - char *pstr, *pfront, tempString[128]; - int j; - - strcpy( tempString, pString ); - pstr = pfront = tempString; - - for ( j = 0; j < count; j++ ) // lifted from pr_edict.c - { - pVector[j] = atoi( pfront ); - - while ( *pstr && *pstr != ' ' ) - pstr++; - if (!*pstr) - break; - pstr++; - pfront = pstr; - } - - for ( j++; j < count; j++ ) - { - pVector[j] = 0; - } -} - -Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ) -{ - Vector sourceVector = input; - - if ( sourceVector.x > clampSize.x ) - sourceVector.x -= clampSize.x; - else if ( sourceVector.x < -clampSize.x ) - sourceVector.x += clampSize.x; - else - sourceVector.x = 0; - - if ( sourceVector.y > clampSize.y ) - sourceVector.y -= clampSize.y; - else if ( sourceVector.y < -clampSize.y ) - sourceVector.y += clampSize.y; - else - sourceVector.y = 0; - - if ( sourceVector.z > clampSize.z ) - sourceVector.z -= clampSize.z; - else if ( sourceVector.z < -clampSize.z ) - sourceVector.z += clampSize.z; - else - sourceVector.z = 0; - - return sourceVector.Normalize(); -} - - -float UTIL_WaterLevel( const Vector &position, float minz, float maxz ) -{ - Vector midUp = position; - midUp.z = minz; - - if (UTIL_PointContents(midUp) != CONTENTS_WATER) - return minz; - - midUp.z = maxz; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - return maxz; - - float diff = maxz - minz; - while (diff > 1.0) - { - midUp.z = minz + diff/2.0; - if (UTIL_PointContents(midUp) == CONTENTS_WATER) - { - minz = midUp.z; - } - else - { - maxz = midUp.z; - } - diff = maxz - minz; - } - - return midUp.z; -} - - -extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model - -void UTIL_Bubbles( Vector mins, Vector maxs, int count ) -{ - Vector mid = (mins + maxs) * 0.5; - - float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 ); - flHeight = flHeight - mins.z; - - MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid ); - WRITE_BYTE( TE_BUBBLES ); - WRITE_COORD( mins.x ); // mins - WRITE_COORD( mins.y ); - WRITE_COORD( mins.z ); - WRITE_COORD( maxs.x ); // maxz - WRITE_COORD( maxs.y ); - WRITE_COORD( maxs.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - -void UTIL_BubbleTrail( Vector from, Vector to, int count ) -{ - float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 ); - flHeight = flHeight - from.z; - - if (flHeight < 8) - { - flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 ); - flHeight = flHeight - to.z; - if (flHeight < 8) - return; - - // UNDONE: do a ploink sound - flHeight = flHeight + to.z - from.z; - } - - if (count > 255) - count = 255; - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); - WRITE_BYTE( TE_BUBBLETRAIL ); - WRITE_COORD( from.x ); // mins - WRITE_COORD( from.y ); - WRITE_COORD( from.z ); - WRITE_COORD( to.x ); // maxz - WRITE_COORD( to.y ); - WRITE_COORD( to.z ); - WRITE_COORD( flHeight ); // height - WRITE_SHORT( g_sModelIndexBubbles ); - WRITE_BYTE( count ); // count - WRITE_COORD( 8 ); // speed - MESSAGE_END(); -} - - -void UTIL_Remove( CBaseEntity *pEntity ) -{ - if ( !pEntity ) - return; - - pEntity->UpdateOnRemove(); - pEntity->pev->flags |= FL_KILLME; - pEntity->pev->targetname = 0; -} - - -BOOL UTIL_IsValidEntity( edict_t *pent ) -{ - if ( !pent || pent->free || (pent->v.flags & FL_KILLME) ) - return FALSE; - return TRUE; -} - - -void UTIL_PrecacheOther( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOther\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - if (pEntity) - pEntity->Precache( ); - REMOVE_ENTITY(pent); -} - -//========================================================= -// UTIL_LogPrintf - Prints a logged message to console. -// Preceded by LOG: ( timestamp ) < message > -//========================================================= -void UTIL_LogPrintf( const char *fmt, ... ) -{ - va_list argptr; - static char string[1024]; - - va_start ( argptr, fmt ); - vsprintf ( string, fmt, argptr ); - va_end ( argptr ); - - // Print to server console - ALERT( at_logged, "%s", string ); -} - -//========================================================= -// UTIL_DotPoints - returns the dot product of a line from -// src to check and vecdir. -//========================================================= -float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ) -{ - Vector2D vec2LOS; - - vec2LOS = ( vecCheck - vecSrc ).Make2D(); - vec2LOS = vec2LOS.Normalize(); - - return DotProduct (vec2LOS , ( vecDir.Make2D() ) ); -} - - -//========================================================= -// UTIL_StripToken - for redundant keynames -//========================================================= -void UTIL_StripToken( const char *pKey, char *pDest ) -{ - int i = 0; - - while ( pKey[i] && pKey[i] != '#' ) - { - pDest[i] = pKey[i]; - i++; - } - pDest[i] = 0; -} - - -// -------------------------------------------------------------- -// -// CSave -// -// -------------------------------------------------------------- -static int gSizes[FIELD_TYPECOUNT] = -{ - sizeof(float), // FIELD_FLOAT - sizeof(int), // FIELD_STRING - sizeof(int), // FIELD_ENTITY - sizeof(int), // FIELD_CLASSPTR - sizeof(int), // FIELD_EHANDLE - sizeof(int), // FIELD_entvars_t - sizeof(int), // FIELD_EDICT - sizeof(float)*3, // FIELD_VECTOR - sizeof(float)*3, // FIELD_POSITION_VECTOR - sizeof(int *), // FIELD_POINTER - sizeof(int), // FIELD_INTEGER -#ifdef GNUC - sizeof(int *)*2, // FIELD_FUNCTION -#else - sizeof(int *), // FIELD_FUNCTION -#endif - sizeof(int), // FIELD_BOOLEAN - sizeof(short), // FIELD_SHORT - sizeof(char), // FIELD_CHARACTER - sizeof(float), // FIELD_TIME - sizeof(int), // FIELD_MODELNAME - sizeof(int), // FIELD_SOUNDNAME -}; - - -// Base class includes common SAVERESTOREDATA pointer, and manages the entity table -CSaveRestoreBuffer :: CSaveRestoreBuffer( void ) -{ - m_pdata = NULL; -} - - -CSaveRestoreBuffer :: CSaveRestoreBuffer( SAVERESTOREDATA *pdata ) -{ - m_pdata = pdata; -} - - -CSaveRestoreBuffer :: ~CSaveRestoreBuffer( void ) -{ -} - -int CSaveRestoreBuffer :: EntityIndex( CBaseEntity *pEntity ) -{ - if ( pEntity == NULL ) - return -1; - return EntityIndex( pEntity->pev ); -} - - -int CSaveRestoreBuffer :: EntityIndex( entvars_t *pevLookup ) -{ - if ( pevLookup == NULL ) - return -1; - return EntityIndex( ENT( pevLookup ) ); -} - -int CSaveRestoreBuffer :: EntityIndex( EOFFSET eoLookup ) -{ - return EntityIndex( ENT( eoLookup ) ); -} - - -int CSaveRestoreBuffer :: EntityIndex( edict_t *pentLookup ) -{ - if ( !m_pdata || pentLookup == NULL ) - return -1; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->pent == pentLookup ) - return i; - } - return -1; -} - - -edict_t *CSaveRestoreBuffer :: EntityFromIndex( int entityIndex ) -{ - if ( !m_pdata || entityIndex < 0 ) - return NULL; - - int i; - ENTITYTABLE *pTable; - - for ( i = 0; i < m_pdata->tableCount; i++ ) - { - pTable = m_pdata->pTable + i; - if ( pTable->id == entityIndex ) - return pTable->pent; - } - return NULL; -} - - -int CSaveRestoreBuffer :: EntityFlagsSet( int entityIndex, int flags ) -{ - if ( !m_pdata || entityIndex < 0 ) - return 0; - if ( entityIndex > m_pdata->tableCount ) - return 0; - - m_pdata->pTable[ entityIndex ].flags |= flags; - - return m_pdata->pTable[ entityIndex ].flags; -} - - -void CSaveRestoreBuffer :: BufferRewind( int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size < size ) - size = m_pdata->size; - - m_pdata->pCurrentData -= size; - m_pdata->size -= size; -} - -#ifndef _WIN32 -extern "C" { -unsigned _rotr ( unsigned val, int shift) -{ - register unsigned lobit; /* non-zero means lo bit set */ - register unsigned num = val; /* number to rotate */ - - shift &= 0x1f; /* modulo 32 -- this will also make - negative shifts work */ - - while (shift--) { - lobit = num & 1; /* get high bit */ - num >>= 1; /* shift right one bit */ - if (lobit) - num |= 0x80000000; /* set hi bit if lo bit was set */ - } - - return num; -} -} -#endif - -unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken ) -{ - unsigned int hash = 0; - - while ( *pszToken ) - hash = _rotr( hash, 4 ) ^ *pszToken++; - - return hash; -} - -unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) -{ - unsigned short hash = (unsigned short)(HashString( pszToken ) % (unsigned)m_pdata->tokenCount ); - -#if _DEBUG - static int tokensparsed = 0; - tokensparsed++; - if ( !m_pdata->tokenCount || !m_pdata->pTokens ) - ALERT( at_error, "No token table array in TokenHash()!" ); -#endif - - for ( int i=0; itokenCount; i++ ) - { -#if _DEBUG - static qboolean beentheredonethat = FALSE; - if ( i > 50 && !beentheredonethat ) - { - beentheredonethat = TRUE; - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" ); - } -#endif - - int index = hash + i; - if ( index >= m_pdata->tokenCount ) - index -= m_pdata->tokenCount; - - if ( !m_pdata->pTokens[index] || strcmp( pszToken, m_pdata->pTokens[index] ) == 0 ) - { - m_pdata->pTokens[index] = (char *)pszToken; - return index; - } - } - - // Token hash table full!!! - // [Consider doing overflow table(s) after the main table & limiting linear hash table search] - ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" ); - return 0; -} - -void CSave :: WriteData( const char *pname, int size, const char *pdata ) -{ - BufferField( pname, size, pdata ); -} - - -void CSave :: WriteShort( const char *pname, const short *data, int count ) -{ - BufferField( pname, sizeof(short) * count, (const char *)data ); -} - - -void CSave :: WriteInt( const char *pname, const int *data, int count ) -{ - BufferField( pname, sizeof(int) * count, (const char *)data ); -} - - -void CSave :: WriteFloat( const char *pname, const float *data, int count ) -{ - BufferField( pname, sizeof(float) * count, (const char *)data ); -} - - -void CSave :: WriteTime( const char *pname, const float *data, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * count ); - for ( i = 0; i < count; i++ ) - { - float tmp = data[0]; - - // Always encode time as a delta from the current time so it can be re-based if loaded in a new level - // Times of 0 are never written to the file, so they will be restored as 0, not a relative time - if ( m_pdata ) - tmp -= m_pdata->time; - - BufferData( (const char *)&tmp, sizeof(float) ); - data ++; - } -} - - -void CSave :: WriteString( const char *pname, const char *pdata ) -{ -#ifdef TOKENIZE - short token = (short)TokenHash( pdata ); - WriteShort( pname, &token, 1 ); -#else - BufferField( pname, strlen(pdata) + 1, pdata ); -#endif -} - - -void CSave :: WriteString( const char *pname, const int *stringId, int count ) -{ - int i, size; - -#ifdef TOKENIZE - short token = (short)TokenHash( STRING( *stringId ) ); - WriteShort( pname, &token, 1 ); -#else -#if 0 - if ( count != 1 ) - ALERT( at_error, "No string arrays!\n" ); - WriteString( pname, (char *)STRING(*stringId) ); -#endif - - size = 0; - for ( i = 0; i < count; i++ ) - size += strlen( STRING( stringId[i] ) ) + 1; - - BufferHeader( pname, size ); - for ( i = 0; i < count; i++ ) - { - const char *pString = STRING(stringId[i]); - BufferData( pString, strlen(pString)+1 ); - } -#endif -} - - -void CSave :: WriteVector( const char *pname, const Vector &value ) -{ - WriteVector( pname, &value.x, 1 ); -} - - -void CSave :: WriteVector( const char *pname, const float *value, int count ) -{ - BufferHeader( pname, sizeof(float) * 3 * count ); - BufferData( (const char *)value, sizeof(float) * 3 * count ); -} - - - -void CSave :: WritePositionVector( const char *pname, const Vector &value ) -{ - - if ( m_pdata && m_pdata->fUseLandmark ) - { - Vector tmp = value - m_pdata->vecLandmarkOffset; - WriteVector( pname, tmp ); - } - - WriteVector( pname, value ); -} - - -void CSave :: WritePositionVector( const char *pname, const float *value, int count ) -{ - int i; - Vector tmp, input; - - BufferHeader( pname, sizeof(float) * 3 * count ); - for ( i = 0; i < count; i++ ) - { - Vector tmp( value[0], value[1], value[2] ); - - if ( m_pdata && m_pdata->fUseLandmark ) - tmp = tmp - m_pdata->vecLandmarkOffset; - - BufferData( (const char *)&tmp.x, sizeof(float) * 3 ); - value += 3; - } -} - - -void CSave :: WriteFunction( const char *pname, void **data, int count ) -{ - const char *functionName; - - functionName = NAME_FOR_FUNCTION( (uint32)*data ); - if ( functionName ) - BufferField( pname, strlen(functionName) + 1, functionName ); - else - ALERT( at_error, "Invalid function pointer in entity!" ); -} - - -void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ) -{ - int i; - TYPEDESCRIPTION *pField; - - for ( i = 0; i < static_cast(ENTVARS_COUNT); i++ ) - { - pField = &gEntvarsDescription[i]; - - if ( !stricmp( pField->fieldName, pkvd->szKeyName ) ) - { - switch( pField->fieldType ) - { - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING( pkvd->szValue ); - break; - - case FIELD_TIME: - case FIELD_FLOAT: - (*(float *)((char *)pev + pField->fieldOffset)) = atof( pkvd->szValue ); - break; - - case FIELD_INTEGER: - (*(int *)((char *)pev + pField->fieldOffset)) = atoi( pkvd->szValue ); - break; - - case FIELD_POSITION_VECTOR: - case FIELD_VECTOR: - UTIL_StringToVector( (float *)((char *)pev + pField->fieldOffset), pkvd->szValue ); - break; - - default: - case FIELD_EVARS: - case FIELD_CLASSPTR: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_POINTER: - ALERT( at_error, "Bad field in entity!!\n" ); - break; - } - pkvd->fHandled = TRUE; - return; - } - } -} - - - -int CSave :: WriteEntVars( const char *pname, entvars_t *pev ) -{ - return WriteFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - - -int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - int i, j, actualCount, emptyCount; - TYPEDESCRIPTION *pTest; - int entityArray[MAX_ENTITYARRAY]; - - // Precalculate the number of empty fields - emptyCount = 0; - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pOutputData = ((char *)pBaseData + pFields[i].fieldOffset ); - if ( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) ) - emptyCount++; - } - - // Empty fields will not be written, write out the actual number of fields to be written - actualCount = fieldCount - emptyCount; - WriteInt( pname, &actualCount, 1 ); - - for ( i = 0; i < fieldCount; i++ ) - { - void *pOutputData; - pTest = &pFields[ i ]; - pOutputData = ((char *)pBaseData + pTest->fieldOffset ); - - // UNDONE: Must we do this twice? - if ( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) ) - continue; - - switch( pTest->fieldType ) - { - case FIELD_FLOAT: - WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_TIME: - WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - WriteString( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - case FIELD_CLASSPTR: - case FIELD_EVARS: - case FIELD_EDICT: - case FIELD_ENTITY: - case FIELD_EHANDLE: - if ( pTest->fieldSize > MAX_ENTITYARRAY ) - ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY ); - for ( j = 0; j < pTest->fieldSize; j++ ) - { - switch( pTest->fieldType ) - { - case FIELD_EVARS: - entityArray[j] = EntityIndex( ((entvars_t **)pOutputData)[j] ); - break; - case FIELD_CLASSPTR: - entityArray[j] = EntityIndex( ((CBaseEntity **)pOutputData)[j] ); - break; - case FIELD_EDICT: - entityArray[j] = EntityIndex( ((edict_t **)pOutputData)[j] ); - break; - case FIELD_ENTITY: - entityArray[j] = EntityIndex( ((EOFFSET *)pOutputData)[j] ); - break; - case FIELD_EHANDLE: - entityArray[j] = EntityIndex( (CBaseEntity *)(((EHANDLE *)pOutputData)[j]) ); - break; - default: - break; - } - } - WriteInt( pTest->fieldName, entityArray, pTest->fieldSize ); - break; - case FIELD_POSITION_VECTOR: - WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - case FIELD_VECTOR: - WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_SHORT: - WriteData( pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData) ); - break; - - case FIELD_CHARACTER: - WriteData( pTest->fieldName, pTest->fieldSize, ((char *)pOutputData) ); - break; - - // For now, just write the address out, we're not going to change memory while doing this yet! - case FIELD_POINTER: - WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); - break; - - case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (void **)pOutputData, pTest->fieldSize ); - break; - default: - ALERT( at_error, "Bad field type\n" ); - } - } - - return 1; -} - - -void CSave :: BufferString( char *pdata, int len ) -{ - char c = 0; - - BufferData( pdata, len ); // Write the string - BufferData( &c, 1 ); // Write a null terminator -} - - -int CSave :: DataEmpty( const char *pdata, int size ) -{ - for ( int i = 0; i < size; i++ ) - { - if ( pdata[i] ) - return 0; - } - return 1; -} - - -void CSave :: BufferField( const char *pname, int size, const char *pdata ) -{ - BufferHeader( pname, size ); - BufferData( pdata, size ); -} - - -void CSave :: BufferHeader( const char *pname, int size ) -{ - short hashvalue = TokenHash( pname ); - if ( size > 1<<(sizeof(short)*8) ) - ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" ); - BufferData( (const char *)&size, sizeof(short) ); - BufferData( (const char *)&hashvalue, sizeof(short) ); -} - - -void CSave :: BufferData( const char *pdata, int size ) -{ - if ( !m_pdata ) - return; - - if ( m_pdata->size + size > m_pdata->bufferSize ) - { - ALERT( at_error, "Save/Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - memcpy( m_pdata->pCurrentData, pdata, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - - -// -------------------------------------------------------------- -// -// CRestore -// -// -------------------------------------------------------------- - -int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ) -{ - int i, j, stringCount, fieldNumber, entityIndex; - TYPEDESCRIPTION *pTest; - float time, timeData; - Vector position; - edict_t *pent; - char *pString; - - time = 0; - position = Vector(0,0,0); - - if ( m_pdata ) - { - time = m_pdata->time; - if ( m_pdata->fUseLandmark ) - position = m_pdata->vecLandmarkOffset; - } - - for ( i = 0; i < fieldCount; i++ ) - { - fieldNumber = (i+startField)%fieldCount; - pTest = &pFields[ fieldNumber ]; - if ( !stricmp( pTest->fieldName, pName ) ) - { - if ( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL) ) - { - for ( j = 0; j < pTest->fieldSize; j++ ) - { - void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j*gSizes[pTest->fieldType]) ); - void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; - - switch( pTest->fieldType ) - { - case FIELD_TIME: - timeData = *(float *)pInputData; - // Re-base time variables - timeData += time; - *((float *)pOutputData) = timeData; - break; - case FIELD_FLOAT: - *((float *)pOutputData) = *(float *)pInputData; - break; - case FIELD_MODELNAME: - case FIELD_SOUNDNAME: - case FIELD_STRING: - // Skip over j strings - pString = (char *)pData; - for ( stringCount = 0; stringCount < j; stringCount++ ) - { - while (*pString) - pString++; - pString++; - } - pInputData = pString; - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - { - int string; - - string = ALLOC_STRING( (char *)pInputData ); - - *((int *)pOutputData) = string; - - if ( !FStringNull( string ) && m_precache ) - { - if ( pTest->fieldType == FIELD_MODELNAME ) - PRECACHE_MODEL( (char *)STRING( string ) ); - else if ( pTest->fieldType == FIELD_SOUNDNAME ) - PRECACHE_SOUND( (char *)STRING( string ) ); - } - } - break; - case FIELD_EVARS: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((entvars_t **)pOutputData) = VARS(pent); - else - *((entvars_t **)pOutputData) = NULL; - break; - case FIELD_CLASSPTR: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); - else - *((CBaseEntity **)pOutputData) = NULL; - break; - case FIELD_EDICT: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - *((edict_t **)pOutputData) = pent; - break; - case FIELD_EHANDLE: - // Input and Output sizes are different! - pOutputData = (char *)pOutputData + j*(sizeof(EHANDLE) - gSizes[pTest->fieldType]); - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); - else - *((EHANDLE *)pOutputData) = NULL; - break; - case FIELD_ENTITY: - entityIndex = *( int *)pInputData; - pent = EntityFromIndex( entityIndex ); - if ( pent ) - *((EOFFSET *)pOutputData) = OFFSET(pent); - else - *((EOFFSET *)pOutputData) = 0; - break; - case FIELD_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0]; - ((float *)pOutputData)[1] = ((float *)pInputData)[1]; - ((float *)pOutputData)[2] = ((float *)pInputData)[2]; - break; - case FIELD_POSITION_VECTOR: - ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; - ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; - ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; - break; - - case FIELD_BOOLEAN: - case FIELD_INTEGER: - *((int *)pOutputData) = *( int *)pInputData; - break; - - case FIELD_SHORT: - *((short *)pOutputData) = *( short *)pInputData; - break; - - case FIELD_CHARACTER: - *((char *)pOutputData) = *( char *)pInputData; - break; - - case FIELD_POINTER: - *((int *)pOutputData) = *( int *)pInputData; - break; - case FIELD_FUNCTION: - if ( strlen( (char *)pInputData ) == 0 ) - *((int *)pOutputData) = 0; - else - *((int *)pOutputData) = FUNCTION_FROM_NAME( (char *)pInputData ); - break; - - default: - ALERT( at_error, "Bad field type\n" ); - } - } - } -#if 0 - else - { - ALERT( at_console, "Skipping global field %s\n", pName ); - } -#endif - return fieldNumber; - } - } - - return -1; -} - - -int CRestore::ReadEntVars( const char *pname, entvars_t *pev ) -{ - return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT ); -} - - -int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ) -{ - unsigned short i, token; - int lastField, fileCount; - HEADER header; - - i = ReadShort(); - ASSERT( i == sizeof(int) ); // First entry should be an int - - token = ReadShort(); - - // Check the struct name - if ( token != TokenHash(pname) ) // Field Set marker - { -// ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() ); - BufferRewind( 2*sizeof(short) ); - return 0; - } - - // Skip over the struct name - fileCount = ReadInt(); // Read field count - - lastField = 0; // Make searches faster, most data is read/written in the same order - - // Clear out base data - for ( i = 0; i < fieldCount; i++ ) - { - // Don't clear global fields - if ( !m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL) ) - memset( ((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ); - } - - for ( i = 0; i < fileCount; i++ ) - { - BufferReadHeader( &header ); - lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData ); - lastField++; - } - - return 1; -} - - -void CRestore::BufferReadHeader( HEADER *pheader ) -{ - ASSERT( pheader!=NULL ); - pheader->size = ReadShort(); // Read field size - pheader->token = ReadShort(); // Read field name token - pheader->pData = BufferPointer(); // Field Data is next - BufferSkipBytes( pheader->size ); // Advance to next field -} - - -short CRestore::ReadShort( void ) -{ - short tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(short) ); - - return tmp; -} - -int CRestore::ReadInt( void ) -{ - int tmp = 0; - - BufferReadBytes( (char *)&tmp, sizeof(int) ); - - return tmp; -} - -int CRestore::ReadNamedInt( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); - return ((int *)header.pData)[0]; -} - -char *CRestore::ReadNamedString( const char *pName ) -{ - HEADER header; - - BufferReadHeader( &header ); -#ifdef TOKENIZE - return (char *)(m_pdata->pTokens[*(short *)header.pData]); -#else - return (char *)header.pData; -#endif -} - - -char *CRestore::BufferPointer( void ) -{ - if ( !m_pdata ) - return NULL; - - return m_pdata->pCurrentData; -} - -void CRestore::BufferReadBytes( char *pOutput, int size ) -{ - ASSERT( m_pdata !=NULL ); - - if ( !m_pdata || Empty() ) - return; - - if ( (m_pdata->size + size) > m_pdata->bufferSize ) - { - ALERT( at_error, "Restore overflow!" ); - m_pdata->size = m_pdata->bufferSize; - return; - } - - if ( pOutput ) - memcpy( pOutput, m_pdata->pCurrentData, size ); - m_pdata->pCurrentData += size; - m_pdata->size += size; -} - - -void CRestore::BufferSkipBytes( int bytes ) -{ - BufferReadBytes( NULL, bytes ); -} - -int CRestore::BufferSkipZString( void ) -{ - char *pszSearch; - int len; - - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - - len = 0; - pszSearch = m_pdata->pCurrentData; - while ( *pszSearch++ && len < maxLen ) - len++; - - len++; - - BufferSkipBytes( len ); - - return len; -} - -int CRestore::BufferCheckZString( const char *string ) -{ - if ( !m_pdata ) - return 0; - - int maxLen = m_pdata->bufferSize - m_pdata->size; - int len = strlen( string ); - if ( len <= maxLen ) - { - if ( !strncmp( string, m_pdata->pCurrentData, len ) ) - return 1; - } - return 0; -} - diff --git a/sdk/dlls/util.h b/sdk/dlls/util.h deleted file mode 100644 index a2e03da..0000000 --- a/sdk/dlls/util.h +++ /dev/null @@ -1,548 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "archtypes.h" // DAL - -// -// Misc utility code -// -#ifndef ACTIVITY_H -#include "activity.h" -#endif - -#ifndef ENGINECALLBACK_H -#include "enginecallback.h" -#endif -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file - -extern globalvars_t *gpGlobals; - -// Use this instead of ALLOC_STRING on constant strings -#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset))) -#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0))) - -inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); -} - -inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); -} - -// for doing a reverse lookup. Say you have a door, and want to find its button. -inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName) -{ - return FIND_ENTITY_BY_STRING(entStart, "target", pszName); -} - -// Keeps clutter down a bit, when writing key-value pairs -#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue) -#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue) -#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue) -#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) \ - ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ) - -// Keeps clutter down a bit, when using a float as a bit-vector -#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) -#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) -#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit)) - -// Makes these more explicit, and easier to find -#define FILE_GLOBAL static -#define DLL_GLOBAL - -// Until we figure out why "const" gives the compiler problems, we'll just have to use -// this bogus "empty" define to mark things as constant. -#define CONSTANT - -// More explicit than "int" -typedef int EOFFSET; - -// In case it's not alread defined -typedef int BOOL; - -// In case this ever changes -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -// Keeps clutter down a bit, when declaring external entity/global method prototypes -#define DECLARE_GLOBAL_METHOD(MethodName) extern void UTIL_DLLEXPORT MethodName( void ) -#define GLOBAL_METHOD(funcname) void UTIL_DLLEXPORT funcname(void) - -#ifndef UTIL_DLLEXPORT -#ifdef _WIN32 -#define UTIL_DLLEXPORT _declspec( dllexport ) -#else -#define UTIL_DLLEXPORT __attribute__ ((visibility("default"))) -#endif -#endif - -// This is the glue that hooks .MAP entity class names to our CPP classes -// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() -// The function is used to intialize / allocate the object for the entity -#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ - extern "C" UTIL_DLLEXPORT void mapClassName( entvars_t *pev ); \ - void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } - - -// -// Conversion among the three types of "entity", including identity-conversions. -// -#ifdef DEBUG - extern edict_t *DBG_EntOfVars(const entvars_t *pev); - inline edict_t *ENT(const entvars_t *pev) { return DBG_EntOfVars(pev); } -#else - inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } -#endif -inline edict_t *ENT(edict_t *pent) { return pent; } -inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } -inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; } -inline EOFFSET OFFSET(const edict_t *pent) -{ -#ifdef _DEBUG - if ( !pent ) - ALERT( at_error, "Bad ent in OFFSET()\n" ); -#endif - return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); -} -inline EOFFSET OFFSET(entvars_t *pev) -{ -#ifdef _DEBUG - if ( !pev ) - ALERT( at_error, "Bad pev in OFFSET()\n" ); -#endif - return OFFSET(ENT(pev)); -} -inline entvars_t *VARS(entvars_t *pev) { return pev; } - -inline entvars_t *VARS(edict_t *pent) -{ - if ( !pent ) - return NULL; - - return &pent->v; -} - -inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } -inline int ENTINDEX(edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } -inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } -inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) { - (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent)); -} - -// Testing the three types of "entity" for nullity -#define eoNullEntity 0 -inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; } -inline BOOL FNullEnt(const edict_t* pent) { return pent == NULL || FNullEnt(OFFSET(pent)); } -inline BOOL FNullEnt(entvars_t* pev) { return pev == NULL || FNullEnt(OFFSET(pev)); } - -// Testing strings for nullity -#define iStringNull 0 -inline BOOL FStringNull(int iString) { return iString == iStringNull; } - -#define cchMapNameMost 32 - -// Dot products for view cone checking -#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees -#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks -#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks -#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks - -// All monsters need this data -#define DONT_BLEED -1 -#define BLOOD_COLOR_RED (BYTE)247 -#define BLOOD_COLOR_YELLOW (BYTE)195 -#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW - -typedef enum -{ - - MONSTERSTATE_NONE = 0, - MONSTERSTATE_IDLE, - MONSTERSTATE_COMBAT, - MONSTERSTATE_ALERT, - MONSTERSTATE_HUNT, - MONSTERSTATE_PRONE, - MONSTERSTATE_SCRIPT, - MONSTERSTATE_PLAYDEAD, - MONSTERSTATE_DEAD - -} MONSTERSTATE; - - - -// Things that toggle (buttons/triggers/doors) need this -typedef enum - { - TS_AT_TOP, - TS_AT_BOTTOM, - TS_GOING_UP, - TS_GOING_DOWN - } TOGGLE_STATE; - -// Misc useful -inline BOOL FStrEq(const char*sz1, const char*sz2) - { return (strcmp(sz1, sz2) == 0); } -inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) - { return FStrEq(STRING(VARS(pent)->classname), szClassname); } -inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) - { return FStrEq(STRING(pev->classname), szClassname); } - -class CBaseEntity; - -// Misc. Prototypes -extern void UTIL_SetSize (entvars_t* pev, const Vector &vecMin, const Vector &vecMax); -extern float UTIL_VecToYaw (const Vector &vec); -extern Vector UTIL_VecToAngles (const Vector &vec); -extern float UTIL_AngleMod (float a); -extern float UTIL_AngleDiff ( float destAngle, float srcAngle ); - -extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius); -extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ); -extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName ); -extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); - -// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected -// otherwise returns NULL -// Index is 1 based -extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); - -#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) -extern void UTIL_MakeVectors (const Vector &vecAngles); - -// Pass in an array of pointers and an array size, it fills the array and returns the number inserted -extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); -extern int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ); - -inline void UTIL_MakeVectorsPrivate( const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp ) -{ - g_engfuncs.pfnAngleVectors( vecAngles, p_vForward, p_vRight, p_vUp ); -} - -extern void UTIL_MakeAimVectors ( const Vector &vecAngles ); // like MakeVectors, but assumes pitch isn't inverted -extern void UTIL_MakeInvVectors ( const Vector &vec, globalvars_t *pgv ); - -extern void UTIL_SetOrigin ( entvars_t* pev, const Vector &vecOrigin ); -extern void UTIL_EmitAmbientSound ( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ); -extern void UTIL_ParticleEffect ( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); -extern void UTIL_ScreenShake ( const Vector ¢er, float amplitude, float frequency, float duration, float radius ); -extern void UTIL_ScreenShakeAll ( const Vector ¢er, float amplitude, float frequency, float duration ); -extern void UTIL_ShowMessage ( const char *pString, CBaseEntity *pPlayer ); -extern void UTIL_ShowMessageAll ( const char *pString ); -extern void UTIL_ScreenFadeAll ( const Vector &color, float fadeTime, float holdTime, int alpha, int flags ); -extern void UTIL_ScreenFade ( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ); - -typedef enum { ignore_monsters=1, dont_ignore_monsters=0, missile=2 } IGNORE_MONSTERS; -typedef enum { ignore_glass=1, dont_ignore_glass=0 } IGNORE_GLASS; -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr); -extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr); -typedef enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 } HULL_TYPE; -extern void UTIL_TraceHull (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr); -extern TraceResult UTIL_GetGlobalTrace (void); -extern void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr); -extern Vector UTIL_GetAimVector (edict_t* pent, float flSpeed); -extern int UTIL_PointContents (const Vector &vec); - -extern int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); -extern void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); -extern void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); -extern Vector UTIL_RandomBloodVector( void ); -extern BOOL UTIL_ShouldShowBlood( int bloodColor ); -extern void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ); -extern void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ); -extern void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ); -extern void UTIL_Sparks( const Vector &position ); -extern void UTIL_Ricochet( const Vector &position, float scale ); -extern void UTIL_StringToVector( float *pVector, const char *pString ); -extern void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); -extern Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ); -extern float UTIL_Approach( float target, float value, float speed ); -extern float UTIL_ApproachAngle( float target, float value, float speed ); -extern float UTIL_AngleDistance( float next, float cur ); - -extern char *UTIL_VarArgs( const char *format, ... ); -extern void UTIL_Remove( CBaseEntity *pEntity ); -extern BOOL UTIL_IsValidEntity( edict_t *pent ); -extern BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); - -// Use for ease-in, ease-out style interpolation (accel/decel) -extern float UTIL_SplineFraction( float value, float scale ); - -// Search for water transition along a vertical line -extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); -extern void UTIL_Bubbles( Vector mins, Vector maxs, int count ); -extern void UTIL_BubbleTrail( Vector from, Vector to, int count ); - -// allows precacheing of other entities -extern void UTIL_PrecacheOther( const char *szClassname ); - -// prints a message to each client -extern void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); -inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) -{ - UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); -} - -class CBasePlayerItem; -class CBasePlayer; -extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); - -// prints messages through the HUD -extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); - -// prints a message to the HUD say (chat) -extern void UTIL_SayText( const char *pText, CBaseEntity *pEntity ); -extern void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ); - - -typedef struct hudtextparms_s -{ - float x; - float y; - int effect; - byte r1, g1, b1, a1; - byte r2, g2, b2, a2; - float fadeinTime; - float fadeoutTime; - float holdTime; - float fxTime; - int channel; -} hudtextparms_t; - -// prints as transparent 'title' to the HUD -extern void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); -extern void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ); - -// for handy use with ClientPrint params -extern char *UTIL_dtos1( int d ); -extern char *UTIL_dtos2( int d ); -extern char *UTIL_dtos3( int d ); -extern char *UTIL_dtos4( int d ); - -// Writes message to console with timestamp and FragLog header. -extern void UTIL_LogPrintf( char *fmt, ... ); - -// Sorta like FInViewCone, but for nonmonsters. -extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); - -extern void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames - -// Misc functions -extern void SetMovedir(entvars_t* pev); -extern Vector VecBModelOrigin( entvars_t* pevBModel ); -extern int BuildChangeList( LEVELLIST *pLevelList, int maxList ); - -// -// How did I ever live without ASSERT? -// -#ifdef DEBUG -void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); -#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL) -#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz) -#else // !DEBUG -#define ASSERT(f) -#define ASSERTSZ(f, sz) -#endif // !DEBUG - - -extern DLL_GLOBAL const Vector g_vecZero; - -// -// Constants that were used only by QC (maybe not used at all now) -// -// Un-comment only as needed -// -#define LANGUAGE_ENGLISH 0 -#define LANGUAGE_GERMAN 1 -#define LANGUAGE_FRENCH 2 -#define LANGUAGE_BRITISH 3 - -extern DLL_GLOBAL int g_Language; - -#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation -#define AMBIENT_SOUND_EVERYWHERE 1 -#define AMBIENT_SOUND_SMALLRADIUS 2 -#define AMBIENT_SOUND_MEDIUMRADIUS 4 -#define AMBIENT_SOUND_LARGERADIUS 8 -#define AMBIENT_SOUND_START_SILENT 16 -#define AMBIENT_SOUND_NOT_LOOPING 32 - -#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements - -#define SND_SPAWNING (1<<8) // duplicated in protocol.h we're spawing, used in some cases for ambients -#define SND_STOP (1<<5) // duplicated in protocol.h stop sound -#define SND_CHANGE_VOL (1<<6) // duplicated in protocol.h change sound vol -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch - -#define LFO_SQUARE 1 -#define LFO_TRIANGLE 2 -#define LFO_RANDOM 3 - -// func_rotating -#define SF_BRUSH_ROTATE_Y_AXIS 0 -#define SF_BRUSH_ROTATE_INSTANT 1 -#define SF_BRUSH_ROTATE_BACKWARDS 2 -#define SF_BRUSH_ROTATE_Z_AXIS 4 -#define SF_BRUSH_ROTATE_X_AXIS 8 -#define SF_PENDULUM_AUTO_RETURN 16 -#define SF_PENDULUM_PASSABLE 32 - - -#define SF_BRUSH_ROTATE_SMALLRADIUS 128 -#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 -#define SF_BRUSH_ROTATE_LARGERADIUS 512 - -#define PUSH_BLOCK_ONLY_X 1 -#define PUSH_BLOCK_ONLY_Y 2 - -#define VEC_HULL_MIN Vector(-16, -16, -36) -#define VEC_HULL_MAX Vector( 16, 16, 36) -#define VEC_HUMAN_HULL_MIN Vector( -16, -16, 0 ) -#define VEC_HUMAN_HULL_MAX Vector( 16, 16, 72 ) -#define VEC_HUMAN_HULL_DUCK Vector( 16, 16, 36 ) - -#define VEC_VIEW Vector( 0, 0, 28 ) - -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) -#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) -#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) - -#define SVC_TEMPENTITY 23 -#define SVC_INTERMISSION 30 -#define SVC_CDTRACK 32 -#define SVC_WEAPONANIM 35 -#define SVC_ROOMTYPE 37 -#define SVC_DIRECTOR 51 - - - -// triggers -#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger -#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger -#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger - -// func breakable -#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger -#define SF_BREAK_TOUCH 2// can be 'crashed through' by running player (plate glass) -#define SF_BREAK_PRESSURE 4// can be broken by a player standing on it -#define SF_BREAK_CROWBAR 256// instant break if hit with crowbar - -// func_pushable (it's also func_breakable, so don't collide with those flags) -#define SF_PUSH_BREAKABLE 128 - -#define SF_LIGHT_START_OFF 1 - -#define SPAWNFLAG_NOMESSAGE 1 -#define SPAWNFLAG_NOTOUCH 1 -#define SPAWNFLAG_DROIDONLY 4 - -#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) - -#define TELE_PLAYER_ONLY 1 -#define TELE_SILENT 2 - -#define SF_TRIG_PUSH_ONCE 1 - - -// Sound Utilities - -// sentence groups -#define CBSENTENCENAME_MAX 16 -#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match - // CVOXFILESENTENCEMAX in engine\sound.h!!! - -extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; -extern int gcallsentences; - -int USENTENCEG_Pick(int isentenceg, char *szfound); -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); -void USENTENCEG_InitLRU(unsigned char *plru, int count); - -void SENTENCEG_Init(); -void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); -int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch); -int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); -int SENTENCEG_GetIndex(const char *szrootname); -int SENTENCEG_Lookup(const char *sample, char *sentencenum); - -void TEXTURETYPE_Init(); -char TEXTURETYPE_Find(char *name); -float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); - -// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 -// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 -// down to 1 is a lower pitch. 150 to 70 is the realistic range. -// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as -// fast as EMIT_SOUND (the pitchshift mixer is not native coded). - -void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, - int flags, int pitch); - - -inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) -{ - EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); -} - -inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) -{ - EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); -} - -void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); -void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); -void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); - -#define PRECACHE_SOUND_ARRAY( a ) \ - { for (int i = 0; i < static_cast(ARRAYSIZE( a )); i++ ) PRECACHE_SOUND((char *) a [i]); } - -#define EMIT_SOUND_ARRAY_DYN( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); - -#define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] - -#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); -#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); - -#define GROUP_OP_AND 0 -#define GROUP_OP_NAND 1 - -extern int g_groupmask; -extern int g_groupop; - -class UTIL_GroupTrace -{ -public: - UTIL_GroupTrace( int groupmask, int op ); - ~UTIL_GroupTrace( void ); - -private: - int m_oldgroupmask, m_oldgroupop; -}; - -void UTIL_SetGroupTrace( int groupmask, int op ); -void UTIL_UnsetGroupTrace( void ); - -int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); - -float UTIL_WeaponTimeBase( void ); diff --git a/sdk/dlls/vector.h b/sdk/dlls/vector.h deleted file mode 100644 index 08148de..0000000 --- a/sdk/dlls/vector.h +++ /dev/null @@ -1,111 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef VECTOR_H -#define VECTOR_H - -//========================================================= -// 2DVector - used for many pathfinding and many other -// operations that are treated as planar rather than 3d. -//========================================================= -class Vector2D -{ -public: - inline Vector2D(void): x(0.0), y(0.0) { } - inline Vector2D(float X, float Y): x(0.0), y(0.0) { x = X; y = Y; } - inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } - inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } - inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } - inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } - - inline float Length(void) const { return sqrt(x*x + y*y ); } - - inline Vector2D Normalize ( void ) const - { - - float flLen = Length(); - if ( flLen == 0 ) - { - return Vector2D( 0, 0 ); - } - else - { - flLen = 1 / flLen; - return Vector2D( x * flLen, y * flLen ); - } - } - - vec_t x, y; -}; - -inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } -inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } - -//========================================================= -// 3D Vector -//========================================================= -class Vector // same data-layout as engine's vec3_t, -{ // which is a vec_t[3] -public: - // Construction/destruction - inline Vector(void): x(0.0), y(0.0), z(0.0) { } - inline Vector(float X, float Y, float Z): x(0.0), y(0.0), z(0.0) { x = X; y = Y; z = Z; } - //inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; } - //inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; } - inline Vector(const Vector& v): x(0.0), y(0.0), z(0.0) { x = v.x; y = v.y; z = v.z; } - inline Vector(float rgfl[3]): x(0.0), y(0.0), z(0.0) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } - - // Operators - inline Vector operator-(void) const { return Vector(-x,-y,-z); } - inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } - inline int operator!=(const Vector& v) const { return !(*this==v); } - inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } - inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } - inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } - inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } - - // Methods - inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } - inline float Length(void) const { return sqrt(x*x + y*y + z*z); } - operator float *() { return &x; } // Vectors will now automatically convert to float * when needed - operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed - inline Vector Normalize(void) const - { - float flLen = Length(); - if (flLen == 0) return Vector(0,0,1); // ???? - flLen = 1 / flLen; - return Vector(x * flLen, y * flLen, z * flLen); - } - - inline Vector2D Make2D ( void ) const - { - Vector2D Vec2; - - Vec2.x = x; - Vec2.y = y; - - return Vec2; - } - inline float Length2D(void) const { return sqrt(x*x + y*y); } - - // Members - vec_t x, y, z; -}; -inline Vector operator*(float fl, const Vector& v) { return v * fl; } -inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } -inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } - - - -#endif diff --git a/sdk/dlls/weapons.cpp b/sdk/dlls/weapons.cpp deleted file mode 100644 index 5c12c90..0000000 --- a/sdk/dlls/weapons.cpp +++ /dev/null @@ -1,1617 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== weapons.cpp ======================================================== - - functions governing the selection/use of weapons for players - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "player.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "soundent.h" -#include "decals.h" -#include "gamerules.h" - -extern CGraph WorldGraph; -extern int gEvilImpulse101; - - -#define NOT_USED 255 - -DLL_GLOBAL short g_sModelIndexLaser;// holds the index for the laser beam -DLL_GLOBAL const char *g_pModelNameLaser = "sprites/laserbeam.spr"; -DLL_GLOBAL short g_sModelIndexLaserDot;// holds the index for the laser beam dot -DLL_GLOBAL short g_sModelIndexFireball;// holds the index for the fireball -DLL_GLOBAL short g_sModelIndexSmoke;// holds the index for the smoke cloud -DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater explosion -DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model -DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood -DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood - -ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; -AmmoInfo CBasePlayerItem::AmmoInfoArray[MAX_AMMO_SLOTS]; - -extern int gmsgCurWeapon; - -MULTIDAMAGE gMultiDamage; - -#define TRACER_FREQ 4 // Tracers fire every fourth bullet - - -//========================================================= -// MaxAmmoCarry - pass in a name and this function will tell -// you the maximum amount of that type of ammunition that a -// player can carry. -//========================================================= -int MaxAmmoCarry( int iszName ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo1 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo1 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo1; - if ( CBasePlayerItem::ItemInfoArray[i].pszAmmo2 && !strcmp( STRING(iszName), CBasePlayerItem::ItemInfoArray[i].pszAmmo2 ) ) - return CBasePlayerItem::ItemInfoArray[i].iMaxAmmo2; - } - - ALERT( at_console, "MaxAmmoCarry() doesn't recognize '%s'!\n", STRING( iszName ) ); - return -1; -} - - -/* -============================================================================== - -MULTI-DAMAGE - -Collects multiple small damages into a single damage - -============================================================================== -*/ - -// -// ClearMultiDamage - resets the global multi damage accumulator -// -void ClearMultiDamage(void) -{ - gMultiDamage.pEntity = NULL; - gMultiDamage.amount = 0; - gMultiDamage.type = 0; -} - - -// -// ApplyMultiDamage - inflicts contents of global multi damage register on gMultiDamage.pEntity -// -// GLOBALS USED: -// gMultiDamage - -void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) -{ - Vector vecSpot1;//where blood comes from - Vector vecDir;//direction blood should go - TraceResult tr; - - if ( !gMultiDamage.pEntity ) - return; - - gMultiDamage.pEntity->TakeDamage(pevInflictor, pevAttacker, gMultiDamage.amount, gMultiDamage.type ); -} - - -// GLOBALS USED: -// gMultiDamage - -void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) -{ - if ( !pEntity ) - return; - - gMultiDamage.type |= bitsDamageType; - - if ( pEntity != gMultiDamage.pEntity ) - { - ApplyMultiDamage(pevInflictor,pevInflictor); // UNDONE: wrong attacker! - gMultiDamage.pEntity = pEntity; - gMultiDamage.amount = 0; - } - - gMultiDamage.amount += flDamage; -} - -/* -================ -SpawnBlood -================ -*/ -void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) -{ - UTIL_BloodDrips( vecSpot, g_vecAttackDir, bloodColor, (int)flDamage ); -} - - -int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) -{ - if ( !pEntity ) - return (DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); - - return pEntity->DamageDecal( bitsDamageType ); -} - -void DecalGunshot( TraceResult *pTrace, int iBulletType ) -{ - // Is the entity valid - if ( !UTIL_IsValidEntity( pTrace->pHit ) ) - return; - - if ( VARS(pTrace->pHit)->solid == SOLID_BSP || VARS(pTrace->pHit)->movetype == MOVETYPE_PUSHSTEP ) - { - CBaseEntity *pEntity = NULL; - // Decal the wall with a gunshot - if ( !FNullEnt(pTrace->pHit) ) - pEntity = CBaseEntity::Instance(pTrace->pHit); - - switch( iBulletType ) - { - case BULLET_PLAYER_9MM: - case BULLET_MONSTER_9MM: - case BULLET_PLAYER_MP5: - case BULLET_MONSTER_MP5: - case BULLET_PLAYER_BUCKSHOT: - case BULLET_PLAYER_357: - default: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); - break; - case BULLET_MONSTER_12MM: - // smoke and decal - UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); - break; - case BULLET_PLAYER_CROWBAR: - // wall decal - UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); - break; - } - } -} - - - -// -// EjectBrass - tosses a brass shell from passed origin at passed velocity -// -void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) -{ - // FIX: when the player shoots, their gun isn't in the same position as it is on the model other players see. - - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE( TE_MODEL); - WRITE_COORD( vecOrigin.x); - WRITE_COORD( vecOrigin.y); - WRITE_COORD( vecOrigin.z); - WRITE_COORD( vecVelocity.x); - WRITE_COORD( vecVelocity.y); - WRITE_COORD( vecVelocity.z); - WRITE_ANGLE( rotation ); - WRITE_SHORT( model ); - WRITE_BYTE ( soundtype); - WRITE_BYTE ( 25 );// 2.5 seconds - MESSAGE_END(); -} - - -#if 0 -// UNDONE: This is no longer used? -void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ) -{ - MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecOrigin ); - WRITE_BYTE ( TE_EXPLODEMODEL ); - WRITE_COORD( vecOrigin.x ); - WRITE_COORD( vecOrigin.y ); - WRITE_COORD( vecOrigin.z ); - WRITE_COORD( speed ); - WRITE_SHORT( model ); - WRITE_SHORT( count ); - WRITE_BYTE ( 15 );// 1.5 seconds - MESSAGE_END(); -} -#endif - - -int giAmmoIndex = 0; - -// Precaches the ammo and queues the ammo info for sending to clients -void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) -{ - // make sure it's not already in the registry - for ( int i = 0; i < MAX_AMMO_SLOTS; i++ ) - { - if ( !CBasePlayerItem::AmmoInfoArray[i].pszName) - continue; - - if ( stricmp( CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname ) == 0 ) - return; // ammo already in registry, just quite - } - - - giAmmoIndex++; - ASSERT( giAmmoIndex < MAX_AMMO_SLOTS ); - if ( giAmmoIndex >= MAX_AMMO_SLOTS ) - giAmmoIndex = 0; - - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].pszName = szAmmoname; - CBasePlayerItem::AmmoInfoArray[giAmmoIndex].iId = giAmmoIndex; // yes, this info is redundant -} - - -// Precaches the weapon and queues the weapon info for sending to clients -void UTIL_PrecacheOtherWeapon( const char *szClassname ) -{ - edict_t *pent; - - pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) ); - if ( FNullEnt( pent ) ) - { - ALERT ( at_console, "NULL Ent in UTIL_PrecacheOtherWeapon\n" ); - return; - } - - CBaseEntity *pEntity = CBaseEntity::Instance (VARS( pent )); - - if (pEntity) - { - ItemInfo II; - pEntity->Precache( ); - memset( &II, 0, sizeof II ); - if ( ((CBasePlayerItem*)pEntity)->GetItemInfo( &II ) ) - { - CBasePlayerItem::ItemInfoArray[II.iId] = II; - - if ( II.pszAmmo1 && *II.pszAmmo1 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo1 ); - } - - if ( II.pszAmmo2 && *II.pszAmmo2 ) - { - AddAmmoNameToAmmoRegistry( II.pszAmmo2 ); - } - - memset( &II, 0, sizeof II ); - } - } - - REMOVE_ENTITY(pent); -} - -// called by worldspawn -void W_Precache(void) -{ - memset( CBasePlayerItem::ItemInfoArray, 0, sizeof(CBasePlayerItem::ItemInfoArray) ); - memset( CBasePlayerItem::AmmoInfoArray, 0, sizeof(CBasePlayerItem::AmmoInfoArray) ); - giAmmoIndex = 0; - - // custom items... - - // common world objects - UTIL_PrecacheOther( "item_suit" ); - UTIL_PrecacheOther( "item_battery" ); - UTIL_PrecacheOther( "item_antidote" ); - UTIL_PrecacheOther( "item_security" ); - UTIL_PrecacheOther( "item_longjump" ); - - // shotgun - UTIL_PrecacheOtherWeapon( "weapon_shotgun" ); - UTIL_PrecacheOther( "ammo_buckshot" ); - - // crowbar - UTIL_PrecacheOtherWeapon( "weapon_crowbar" ); - - // glock - UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" ); - UTIL_PrecacheOther( "ammo_9mmclip" ); - - // mp5 - UTIL_PrecacheOtherWeapon( "weapon_9mmAR" ); - UTIL_PrecacheOther( "ammo_9mmAR" ); - UTIL_PrecacheOther( "ammo_ARgrenades" ); - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // python - UTIL_PrecacheOtherWeapon( "weapon_357" ); - UTIL_PrecacheOther( "ammo_357" ); -#endif - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // gauss - UTIL_PrecacheOtherWeapon( "weapon_gauss" ); - UTIL_PrecacheOther( "ammo_gaussclip" ); -#endif - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // rpg - UTIL_PrecacheOtherWeapon( "weapon_rpg" ); - UTIL_PrecacheOther( "ammo_rpgclip" ); -#endif - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // crossbow - UTIL_PrecacheOtherWeapon( "weapon_crossbow" ); - UTIL_PrecacheOther( "ammo_crossbow" ); -#endif - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // egon - UTIL_PrecacheOtherWeapon( "weapon_egon" ); -#endif - - // tripmine - UTIL_PrecacheOtherWeapon( "weapon_tripmine" ); - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // satchel charge - UTIL_PrecacheOtherWeapon( "weapon_satchel" ); -#endif - - // hand grenade - UTIL_PrecacheOtherWeapon("weapon_handgrenade"); - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // squeak grenade - UTIL_PrecacheOtherWeapon( "weapon_snark" ); -#endif - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - // hornetgun - UTIL_PrecacheOtherWeapon( "weapon_hornetgun" ); -#endif - - -#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) - if ( g_pGameRules->IsDeathmatch() ) - { - UTIL_PrecacheOther( "weaponbox" );// container for dropped deathmatch weapons - } -#endif - - g_sModelIndexFireball = PRECACHE_MODEL ("sprites/zerogxplode.spr");// fireball - g_sModelIndexWExplosion = PRECACHE_MODEL ("sprites/WXplo1.spr");// underwater fireball - g_sModelIndexSmoke = PRECACHE_MODEL ("sprites/steam1.spr");// smoke - g_sModelIndexBubbles = PRECACHE_MODEL ("sprites/bubble.spr");//bubbles - g_sModelIndexBloodSpray = PRECACHE_MODEL ("sprites/bloodspray.spr"); // initial blood - g_sModelIndexBloodDrop = PRECACHE_MODEL ("sprites/blood.spr"); // splattered blood - - g_sModelIndexLaser = PRECACHE_MODEL( (char *)g_pModelNameLaser ); - g_sModelIndexLaserDot = PRECACHE_MODEL("sprites/laserdot.spr"); - - - // used by explosions - PRECACHE_MODEL ("models/grenade.mdl"); - PRECACHE_MODEL ("sprites/explode1.spr"); - - PRECACHE_SOUND ("weapons/debris1.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris2.wav");// explosion aftermaths - PRECACHE_SOUND ("weapons/debris3.wav");// explosion aftermaths - - PRECACHE_SOUND ("weapons/grenade_hit1.wav");//grenade - PRECACHE_SOUND ("weapons/grenade_hit2.wav");//grenade - PRECACHE_SOUND ("weapons/grenade_hit3.wav");//grenade - - PRECACHE_SOUND ("weapons/bullet_hit1.wav"); // hit by bullet - PRECACHE_SOUND ("weapons/bullet_hit2.wav"); // hit by bullet - - PRECACHE_SOUND ("items/weapondrop1.wav");// weapon falls to the ground - -} - - - - -TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = -{ - DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), - DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), - //DEFINE_FIELD( CBasePlayerItem, m_fKnown, FIELD_INTEGER ),Reset to zero on load - DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ), - // DEFINE_FIELD( CBasePlayerItem, m_iIdPrimary, FIELD_INTEGER ), - // DEFINE_FIELD( CBasePlayerItem, m_iIdSecondary, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); - - -TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = -{ -#if defined( CLIENT_WEAPONS ) - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_FLOAT ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_FLOAT ), -#else // CLIENT_WEAPONS - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), -#endif // CLIENT_WEAPONS - DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), - DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), -// DEFINE_FIELD( CBasePlayerWeapon, m_iClientClip, FIELD_INTEGER ) , reset to zero on load so hud gets updated correctly -// DEFINE_FIELD( CBasePlayerWeapon, m_iClientWeaponState, FIELD_INTEGER ), reset to zero on load so hud gets updated correctly -}; - -IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); - - -void CBasePlayerItem :: SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-24, -24, 0); - pev->absmax = pev->origin + Vector(24, 24, 16); -} - - -//========================================================= -// Sets up movetype, size, solidtype for a new weapon. -//========================================================= -void CBasePlayerItem :: FallInit( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_BBOX; - - UTIL_SetOrigin( pev, pev->origin ); - UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0) );//pointsize until it lands on the ground. - - SetTouch( &CBasePlayerItem::DefaultTouch ); - SetThink( &CBasePlayerItem::FallThink ); - - pev->nextthink = gpGlobals->time + 0.1; -} - -//========================================================= -// FallThink - Items that have just spawned run this think -// to catch them when they hit the ground. Once we're sure -// that the object is grounded, we change its solid type -// to trigger and set it in a large box that helps the -// player get it. -//========================================================= -void CBasePlayerItem::FallThink ( void ) -{ - pev->nextthink = gpGlobals->time + 0.1; - - if ( pev->flags & FL_ONGROUND ) - { - // clatter if we have an owner (i.e., dropped by someone) - // don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!) - if ( !FNullEnt( pev->owner ) ) - { - int pitch = 95 + RANDOM_LONG(0,29); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "items/weapondrop1.wav", 1, ATTN_NORM, 0, pitch); - } - - // lie flat - pev->angles.x = 0; - pev->angles.z = 0; - - Materialize(); - } -} - -//========================================================= -// Materialize - make a CBasePlayerItem visible and tangible -//========================================================= -void CBasePlayerItem::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - pev->solid = SOLID_TRIGGER; - - UTIL_SetOrigin( pev, pev->origin );// link into world. - SetTouch (&CBasePlayerItem::DefaultTouch); - SetThink (NULL); - -} - -//========================================================= -// AttemptToMaterialize - the item is trying to rematerialize, -// should it do so now or wait longer? -//========================================================= -void CBasePlayerItem::AttemptToMaterialize( void ) -{ - float time = g_pGameRules->FlWeaponTryRespawn( this ); - - if ( time == 0 ) - { - Materialize(); - return; - } - - pev->nextthink = gpGlobals->time + time; -} - -//========================================================= -// CheckRespawn - a player is taking this weapon, should -// it respawn? -//========================================================= -void CBasePlayerItem :: CheckRespawn ( void ) -{ - switch ( g_pGameRules->WeaponShouldRespawn( this ) ) - { - case GR_WEAPON_RESPAWN_YES: - Respawn(); - break; - case GR_WEAPON_RESPAWN_NO: - return; - break; - } -} - -//========================================================= -// Respawn- this item is already in the world, but it is -// invisible and intangible. Make it visible and tangible. -//========================================================= -CBaseEntity* CBasePlayerItem::Respawn( void ) -{ - // make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code - // will decide when to make the weapon visible and touchable. - CBaseEntity *pNewWeapon = CBaseEntity::Create( (char *)STRING( pev->classname ), g_pGameRules->VecWeaponRespawnSpot( this ), pev->angles, pev->owner ); - - if ( pNewWeapon ) - { - pNewWeapon->pev->effects |= EF_NODRAW;// invisible for now - pNewWeapon->SetTouch( NULL );// no touch - pNewWeapon->SetThink( &CBasePlayerItem::AttemptToMaterialize ); - - DROP_TO_FLOOR ( ENT(pev) ); - - // not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement, - // but when it should respawn is based on conditions belonging to the weapon that was taken. - pNewWeapon->pev->nextthink = g_pGameRules->FlWeaponRespawnTime( this ); - } - else - { - ALERT ( at_console, "Respawn failed to create %s!\n", STRING( pev->classname ) ); - } - - return pNewWeapon; -} - -void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) -{ - // if it's not a player, ignore - if ( !pOther->IsPlayer() ) - return; - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - - // can I have this? - if ( !g_pGameRules->CanHavePlayerItem( pPlayer, this ) ) - { - if ( gEvilImpulse101 ) - { - UTIL_Remove( this ); - } - return; - } - - if (pOther->AddPlayerItem( this )) - { - AttachToPlayer( pPlayer ); - EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM); - } - - SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? -} - -BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) -{ -#if defined( CLIENT_WEAPONS ) - if ( !isPredicted ) -#else - if ( 1 ) -#endif - { - return ( attack_time <= curtime ) ? TRUE : FALSE; - } - else - { - return ( attack_time <= 0.0 ) ? TRUE : FALSE; - } -} - -void CBasePlayerWeapon::ItemPostFrame( void ) -{ - if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) - { - // complete the reload. - int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - // Add them to the clip - m_iClip += j; - m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; - - m_pPlayer->TabulateAmmo(); - - m_fInReload = FALSE; - } - - if ( !(m_pPlayer->pev->button & IN_ATTACK ) ) - { - m_flLastFireTime = 0.0f; - } - - if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - SecondaryAttack(); - m_pPlayer->pev->button &= ~IN_ATTACK2; - } - else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) - { - if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) - { - m_fFireOnEmpty = TRUE; - } - - m_pPlayer->TabulateAmmo(); - PrimaryAttack(); - } - else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) - { - // reload when reload is pressed, or if no buttons are down and weapon is empty. - Reload(); - } - else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) - { - // no fire buttons down - - m_fFireOnEmpty = FALSE; - - if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - // weapon isn't useable, switch. - if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) - { - m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; - return; - } - } - else - { - // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) - { - Reload(); - return; - } - } - - WeaponIdle( ); - return; - } - - // catch all - if ( ShouldWeaponIdle() ) - { - WeaponIdle(); - } -} - -void CBasePlayerItem::DestroyItem( void ) -{ - if ( m_pPlayer ) - { - // if attached to a player, remove. - m_pPlayer->RemovePlayerItem( this ); - } - - Kill( ); -} - -int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) -{ - m_pPlayer = pPlayer; - - return TRUE; -} - -void CBasePlayerItem::Drop( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Kill( void ) -{ - SetTouch( NULL ); - SetThink(&CBasePlayerItem::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; -} - -void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) -{ - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) -{ - pev->movetype = MOVETYPE_FOLLOW; - pev->solid = SOLID_NOT; - pev->aiment = pPlayer->edict(); - pev->effects = EF_NODRAW; // ?? - pev->modelindex = 0;// server won't send down to clients if modelindex == 0 - pev->model = iStringNull; - pev->owner = pPlayer->edict(); - pev->nextthink = gpGlobals->time + .1; - SetTouch( NULL ); -} - -// CALLED THROUGH the newly-touched weapon's instance. The existing player weapon is pOriginal -int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) -{ - if ( m_iDefaultAmmo ) - { - return ExtractAmmo( (CBasePlayerWeapon *)pOriginal ); - } - else - { - // a dead player dropped this. - return ExtractClipAmmo( (CBasePlayerWeapon *)pOriginal ); - } -} - - -int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) -{ - int bResult = CBasePlayerItem::AddToPlayer( pPlayer ); - - pPlayer->pev->weapons |= (1<GetAmmoIndex( pszAmmo1() ); - m_iSecondaryAmmoType = pPlayer->GetAmmoIndex( pszAmmo2() ); - } - - - if (bResult) - return AddWeapon( ); - return FALSE; -} - -int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) -{ - BOOL bSend = FALSE; - int state = 0; - if ( pPlayer->m_pActiveItem == this ) - { - if ( pPlayer->m_fOnTarget ) - state = WEAPON_IS_ONTARGET; - else - state = 1; - } - - // Forcing send of all data! - if ( !pPlayer->m_fWeapon ) - { - bSend = TRUE; - } - - // This is the current or last weapon, so the state will need to be updated - if ( this == pPlayer->m_pActiveItem || - this == pPlayer->m_pClientActiveItem ) - { - if ( pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem ) - { - bSend = TRUE; - } - } - - // If the ammo, state, or fov has changed, update the weapon - if ( m_iClip != m_iClientClip || - state != m_iClientWeaponState || - pPlayer->m_iFOV != pPlayer->m_iClientFOV ) - { - bSend = TRUE; - } - - if ( bSend ) - { - MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pPlayer->pev ); - WRITE_BYTE( state ); - WRITE_BYTE( m_iId ); - WRITE_BYTE( m_iClip ); - MESSAGE_END(); - - m_iClientClip = m_iClip; - m_iClientWeaponState = state; - pPlayer->m_fWeapon = TRUE; - } - - if ( m_pNext ) - m_pNext->UpdateClientData( pPlayer ); - - return 1; -} - - -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) -{ - if ( UseDecrement() ) - skiplocal = 1; - else - skiplocal = 0; - - m_pPlayer->pev->weaponanim = iAnim; - -#if defined( CLIENT_WEAPONS ) - if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) - return; -#endif - - MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); - WRITE_BYTE( iAnim ); // sequence number - WRITE_BYTE( pev->body ); // weaponmodel bodygroup. - MESSAGE_END(); -} - -BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) -{ - int iIdAmmo; - - if (iMaxClip < 1) - { - m_iClip = -1; - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - else if (m_iClip == 0) - { - int i; - i = min( m_iClip + iCount, iMaxClip ) - m_iClip; - m_iClip += i; - iIdAmmo = m_pPlayer->GiveAmmo( iCount - i, szName, iMaxCarry ); - } - else - { - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMaxCarry ); - } - - // m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] = iMaxCarry; // hack for testing - - if (iIdAmmo > 0) - { - m_iPrimaryAmmoType = iIdAmmo; - if (m_pPlayer->HasPlayerItem( this ) ) - { - // play the "got ammo" sound only if we gave some ammo to a player that already had this gun. - // if the player is just getting this gun for the first time, DefaultTouch will play the "picked up gun" sound for us. - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - } - - return iIdAmmo > 0 ? TRUE : FALSE; -} - - -BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) -{ - int iIdAmmo; - - iIdAmmo = m_pPlayer->GiveAmmo( iCount, szName, iMax ); - - //m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] = iMax; // hack for testing - - if (iIdAmmo > 0) - { - m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - } - return iIdAmmo > 0 ? TRUE : FALSE; -} - -//========================================================= -// IsUseable - this function determines whether or not a -// weapon is useable by the player in its current state. -// (does it have ammo loaded? do I have any ammo for the -// weapon?, etc) -//========================================================= -BOOL CBasePlayerWeapon :: IsUseable( void ) -{ - if ( m_iClip <= 0 ) - { - if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) - { - // clip is empty (or nonexistant) and the player has no more ammo of this type. - return FALSE; - } - } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: CanDeploy( void ) -{ - BOOL bHasAmmo = 0; - - if ( !pszAmmo1() ) - { - // this weapon doesn't use ammo, can always deploy. - return TRUE; - } - - if ( pszAmmo1() ) - { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); - } - if ( pszAmmo2() ) - { - bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); - } - if (m_iClip > 0) - { - bHasAmmo |= 1; - } - if (!bHasAmmo) - { - return FALSE; - } - - return TRUE; -} - -BOOL CBasePlayerWeapon :: DefaultDeploy( const char *szViewModel, const char *szWeaponModel, int iAnim, const char *szAnimExt, int skiplocal /* = 0 */, int body ) -{ - if (!CanDeploy( )) - return FALSE; - - m_pPlayer->TabulateAmmo(); - m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); - m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); - strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); - SendWeaponAnim( iAnim, skiplocal, body ); - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; - m_flLastFireTime = 0.0; - - return TRUE; -} - - -BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) -{ - if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - return FALSE; - - int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); - - if (j == 0) - return FALSE; - - m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; - - //!!UNDONE -- reload sound goes here !!! - SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); - - m_fInReload = TRUE; - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; - return TRUE; -} - -BOOL CBasePlayerWeapon :: PlayEmptySound( void ) -{ - if (m_iPlayEmptySound) - { - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_iPlayEmptySound = 0; - return 0; - } - return 0; -} - -void CBasePlayerWeapon :: ResetEmptySound( void ) -{ - m_iPlayEmptySound = 1; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::PrimaryAmmoIndex( void ) -{ - return m_iPrimaryAmmoType; -} - -//========================================================= -//========================================================= -int CBasePlayerWeapon::SecondaryAmmoIndex( void ) -{ - return -1; -} - -void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) -{ - m_fInReload = FALSE; // cancel any reload in progress. - m_pPlayer->pev->viewmodel = 0; - m_pPlayer->pev->weaponmodel = 0; -} - -void CBasePlayerAmmo::Spawn( void ) -{ - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 16)); - UTIL_SetOrigin( pev, pev->origin ); - - SetTouch( &CBasePlayerAmmo::DefaultTouch ); -} - -CBaseEntity* CBasePlayerAmmo::Respawn( void ) -{ - pev->effects |= EF_NODRAW; - SetTouch( NULL ); - - UTIL_SetOrigin( pev, g_pGameRules->VecAmmoRespawnSpot( this ) );// move to wherever I'm supposed to repawn. - - SetThink( &CBasePlayerAmmo::Materialize ); - pev->nextthink = g_pGameRules->FlAmmoRespawnTime( this ); - - return this; -} - -void CBasePlayerAmmo::Materialize( void ) -{ - if ( pev->effects & EF_NODRAW ) - { - // changing from invisible state to visible. - EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "items/suitchargeok1.wav", 1, ATTN_NORM, 0, 150 ); - pev->effects &= ~EF_NODRAW; - pev->effects |= EF_MUZZLEFLASH; - } - - SetTouch( &CBasePlayerAmmo::DefaultTouch ); -} - -void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() ) - { - return; - } - - if (AddAmmo( pOther )) - { - if ( g_pGameRules->AmmoShouldRespawn( this ) == GR_AMMO_RESPAWN_YES ) - { - Respawn(); - } - else - { - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } - } - else if (gEvilImpulse101) - { - // evil impulse 101 hack, kill always - SetTouch( NULL ); - SetThink(&CBasePlayerAmmo::SUB_Remove); - pev->nextthink = gpGlobals->time + .1; - } -} - -//========================================================= -// called by the new item with the existing item as parameter -// -// if we call ExtractAmmo(), it's because the player is picking up this type of weapon for -// the first time. If it is spawned by the world, m_iDefaultAmmo will have a default ammo amount in it. -// if this is a weapon dropped by a dying player, has 0 m_iDefaultAmmo, which means only the ammo in -// the weapon clip comes along. -//========================================================= -int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iReturn = 0; - - if ( pszAmmo1() != NULL ) - { - // blindly call with m_iDefaultAmmo. It's either going to be a value or zero. If it is zero, - // we only get the ammo in the weapon's clip, which is what we want. - iReturn = pWeapon->AddPrimaryAmmo( m_iDefaultAmmo, (char *)pszAmmo1(), iMaxClip(), iMaxAmmo1() ); - m_iDefaultAmmo = 0; - } - - if ( pszAmmo2() != NULL ) - { - iReturn = pWeapon->AddSecondaryAmmo( 0, (char *)pszAmmo2(), iMaxAmmo2() ); - } - - return iReturn; -} - -//========================================================= -// called by the new item's class with the existing item as parameter -//========================================================= -int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) -{ - int iAmmo; - - if ( m_iClip == WEAPON_NOCLIP ) - { - iAmmo = 0;// guns with no clips always come empty if they are second-hand - } - else - { - iAmmo = m_iClip; - } - - return pWeapon->m_pPlayer->GiveAmmo( iAmmo, (char *)pszAmmo1(), iMaxAmmo1() ); // , &m_iPrimaryAmmoType -} - -//========================================================= -// RetireWeapon - no more ammo for this gun, put it away. -//========================================================= -void CBasePlayerWeapon::RetireWeapon( void ) -{ - // first, no viewmodel at all. - m_pPlayer->pev->viewmodel = iStringNull; - m_pPlayer->pev->weaponmodel = iStringNull; - //m_pPlayer->pev->viewmodelindex = NULL; - - g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); -} - -//========================================================================= -// GetNextAttackDelay - An accurate way of calcualting the next attack time. -//========================================================================= -float CBasePlayerWeapon::GetNextAttackDelay( float delay ) -{ - if(m_flLastFireTime == 0 || m_flNextPrimaryAttack == -1) - { - // At this point, we are assuming that the client has stopped firing - // and we are going to reset our book keeping variables. - m_flLastFireTime = gpGlobals->time; - m_flPrevPrimaryAttack = delay; - } - // calculate the time between this shot and the previous - float flTimeBetweenFires = gpGlobals->time - m_flLastFireTime; - float flCreep = 0.0f; - if(flTimeBetweenFires > 0) - flCreep = flTimeBetweenFires - m_flPrevPrimaryAttack; // postive or negative - - // save the last fire time - m_flLastFireTime = gpGlobals->time; - - float flNextAttack = UTIL_WeaponTimeBase() + delay - flCreep; - // we need to remember what the m_flNextPrimaryAttack time is set to for each shot, - // store it as m_flPrevPrimaryAttack. - m_flPrevPrimaryAttack = flNextAttack - UTIL_WeaponTimeBase(); -// char szMsg[256]; -// _snprintf( szMsg, sizeof(szMsg), "next attack time: %0.4f\n", gpGlobals->time + flNextAttack ); -// OutputDebugString( szMsg ); - return flNextAttack; -} - - -//********************************************************* -// weaponbox code: -//********************************************************* - -LINK_ENTITY_TO_CLASS( weaponbox, CWeaponBox ); - -TYPEDESCRIPTION CWeaponBox::m_SaveData[] = -{ - DEFINE_ARRAY( CWeaponBox, m_rgAmmo, FIELD_INTEGER, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgiszAmmo, FIELD_STRING, MAX_AMMO_SLOTS ), - DEFINE_ARRAY( CWeaponBox, m_rgpPlayerItems, FIELD_CLASSPTR, MAX_ITEM_TYPES ), - DEFINE_FIELD( CWeaponBox, m_cAmmoTypes, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CWeaponBox, CBaseEntity ); - -//========================================================= -// -//========================================================= -void CWeaponBox::Precache( void ) -{ - PRECACHE_MODEL("models/w_weaponbox.mdl"); -} - -//========================================================= -//========================================================= -void CWeaponBox :: KeyValue( KeyValueData *pkvd ) -{ - if ( m_cAmmoTypes < MAX_AMMO_SLOTS ) - { - PackAmmo( ALLOC_STRING(pkvd->szKeyName), atoi(pkvd->szValue) ); - m_cAmmoTypes++;// count this new ammo type. - - pkvd->fHandled = TRUE; - } - else - { - ALERT ( at_console, "WeaponBox too full! only %d ammotypes allowed\n", MAX_AMMO_SLOTS ); - } -} - -//========================================================= -// CWeaponBox - Spawn -//========================================================= -void CWeaponBox::Spawn( void ) -{ - Precache( ); - - pev->movetype = MOVETYPE_TOSS; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, g_vecZero, g_vecZero ); - - SET_MODEL( ENT(pev), "models/w_weaponbox.mdl"); -} - -//========================================================= -// CWeaponBox - Kill - the think function that removes the -// box from the world. -//========================================================= -void CWeaponBox::Kill( void ) -{ - CBasePlayerItem *pWeapon; - int i; - - // destroy the weapons - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - pWeapon = m_rgpPlayerItems[ i ]; - - while ( pWeapon ) - { - pWeapon->SetThink(&CBasePlayerItem::SUB_Remove); - pWeapon->pev->nextthink = gpGlobals->time + 0.1; - pWeapon = pWeapon->m_pNext; - } - } - - // remove the box - UTIL_Remove( this ); -} - -//========================================================= -// CWeaponBox - Touch: try to add my contents to the toucher -// if the toucher is a player. -//========================================================= -void CWeaponBox::Touch( CBaseEntity *pOther ) -{ - if ( !(pev->flags & FL_ONGROUND ) ) - { - return; - } - - if ( !pOther->IsPlayer() ) - { - // only players may touch a weaponbox. - return; - } - - if ( !pOther->IsAlive() ) - { - // no dead guys. - return; - } - - CBasePlayer *pPlayer = (CBasePlayer *)pOther; - int i; - -// dole out ammo - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // there's some ammo of this type. - pPlayer->GiveAmmo( m_rgAmmo[ i ], (char *)STRING( m_rgiszAmmo[ i ] ), MaxAmmoCarry( m_rgiszAmmo[ i ] ) ); - - //ALERT ( at_console, "Gave %d rounds of %s\n", m_rgAmmo[i], STRING(m_rgiszAmmo[i]) ); - - // now empty the ammo from the weaponbox since we just gave it to the player - m_rgiszAmmo[ i ] = iStringNull; - m_rgAmmo[ i ] = 0; - } - } - -// go through my weapons and try to give the usable ones to the player. -// it's important the the player be given ammo first, so the weapons code doesn't refuse -// to deploy a better weapon that the player may pick up because he has no ammo for it. - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - CBasePlayerItem *pItem; - - // have at least one weapon in this slot - while ( m_rgpPlayerItems[ i ] ) - { - //ALERT ( at_console, "trying to give %s\n", STRING( m_rgpPlayerItems[ i ]->pev->classname ) ); - - pItem = m_rgpPlayerItems[ i ]; - m_rgpPlayerItems[ i ] = m_rgpPlayerItems[ i ]->m_pNext;// unlink this weapon from the box - - if ( pPlayer->AddPlayerItem( pItem ) ) - { - pItem->AttachToPlayer( pPlayer ); - } - } - } - } - - EMIT_SOUND( pOther->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - SetTouch(NULL); - UTIL_Remove(this); -} - -//========================================================= -// CWeaponBox - PackWeapon: Add this weapon to the box -//========================================================= -BOOL CWeaponBox::PackWeapon( CBasePlayerItem *pWeapon ) -{ - // is one of these weapons already packed in this box? - if ( HasWeapon( pWeapon ) ) - { - return FALSE;// box can only hold one of each weapon type - } - - if ( pWeapon->m_pPlayer ) - { - if ( !pWeapon->m_pPlayer->RemovePlayerItem( pWeapon ) ) - { - // failed to unhook the weapon from the player! - return FALSE; - } - } - - int iWeaponSlot = pWeapon->iItemSlot(); - - if ( m_rgpPlayerItems[ iWeaponSlot ] ) - { - // there's already one weapon in this slot, so link this into the slot's column - pWeapon->m_pNext = m_rgpPlayerItems[ iWeaponSlot ]; - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - } - else - { - // first weapon we have for this slot - m_rgpPlayerItems[ iWeaponSlot ] = pWeapon; - pWeapon->m_pNext = NULL; - } - - pWeapon->pev->spawnflags |= SF_NORESPAWN;// never respawn - pWeapon->pev->movetype = MOVETYPE_NONE; - pWeapon->pev->solid = SOLID_NOT; - pWeapon->pev->effects = EF_NODRAW; - pWeapon->pev->modelindex = 0; - pWeapon->pev->model = iStringNull; - pWeapon->pev->owner = edict(); - pWeapon->SetThink( NULL );// crowbar may be trying to swing again, etc. - pWeapon->SetTouch( NULL ); - pWeapon->m_pPlayer = NULL; - - //ALERT ( at_console, "packed %s\n", STRING(pWeapon->pev->classname) ); - - return TRUE; -} - -//========================================================= -// CWeaponBox - PackAmmo -//========================================================= -BOOL CWeaponBox::PackAmmo( int iszName, int iCount ) -{ - int iMaxCarry; - - if ( FStringNull( iszName ) ) - { - // error here - ALERT ( at_console, "NULL String in PackAmmo!\n" ); - return FALSE; - } - - iMaxCarry = MaxAmmoCarry( iszName ); - - if ( iMaxCarry != -1 && iCount > 0 ) - { - //ALERT ( at_console, "Packed %d rounds of %s\n", iCount, STRING(iszName) ); - GiveAmmo( iCount, (char *)STRING( iszName ), iMaxCarry ); - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox - GiveAmmo -//========================================================= -int CWeaponBox::GiveAmmo( int iCount, const char *szName, int iMax, int *pIndex/* = NULL*/ ) -{ - int i; - - for (i = 1; i < MAX_AMMO_SLOTS && !FStringNull( m_rgiszAmmo[i] ); i++) - { - if (stricmp( szName, STRING( m_rgiszAmmo[i])) == 0) - { - if (pIndex) - *pIndex = i; - - int iAdd = min( iCount, iMax - m_rgAmmo[i]); - if (iCount == 0 || iAdd > 0) - { - m_rgAmmo[i] += iAdd; - - return i; - } - return -1; - } - } - if (i < MAX_AMMO_SLOTS) - { - if (pIndex) - *pIndex = i; - - m_rgiszAmmo[i] = MAKE_STRING( szName ); - m_rgAmmo[i] = iCount; - - return i; - } - ALERT( at_console, "out of named ammo slots\n"); - return i; -} - -//========================================================= -// CWeaponBox::HasWeapon - is a weapon of this type already -// packed in this box? -//========================================================= -BOOL CWeaponBox::HasWeapon( CBasePlayerItem *pCheckItem ) -{ - CBasePlayerItem *pItem = m_rgpPlayerItems[pCheckItem->iItemSlot()]; - - while (pItem) - { - if (FClassnameIs( pItem->pev, STRING( pCheckItem->pev->classname) )) - { - return TRUE; - } - pItem = pItem->m_pNext; - } - - return FALSE; -} - -//========================================================= -// CWeaponBox::IsEmpty - is there anything in this box? -//========================================================= -BOOL CWeaponBox::IsEmpty( void ) -{ - int i; - - for ( i = 0 ; i < MAX_ITEM_TYPES ; i++ ) - { - if ( m_rgpPlayerItems[ i ] ) - { - return FALSE; - } - } - - for ( i = 0 ; i < MAX_AMMO_SLOTS ; i++ ) - { - if ( !FStringNull( m_rgiszAmmo[ i ] ) ) - { - // still have a bit of this type of ammo - return FALSE; - } - } - - return TRUE; -} - -//========================================================= -//========================================================= -void CWeaponBox::SetObjectCollisionBox( void ) -{ - pev->absmin = pev->origin + Vector(-16, -16, 0); - pev->absmax = pev->origin + Vector(16, 16, 16); -} - - -void CBasePlayerWeapon::PrintState( void ) -{ - ALERT( at_console, "primary: %f\n", m_flNextPrimaryAttack ); - ALERT( at_console, "idle : %f\n", m_flTimeWeaponIdle ); - -// ALERT( at_console, "nextrl : %f\n", m_flNextReload ); -// ALERT( at_console, "nextpum: %f\n", m_flPumpTime ); - -// ALERT( at_console, "m_frt : %f\n", m_fReloadTime ); - ALERT( at_console, "m_finre: %i\n", m_fInReload ); -// ALERT( at_console, "m_finsr: %i\n", m_fInSpecialReload ); - - ALERT( at_console, "m_iclip: %i\n", m_iClip ); -} - - -TYPEDESCRIPTION CRpg::m_SaveData[] = -{ - DEFINE_FIELD( CRpg, m_fSpotActive, FIELD_INTEGER ), - DEFINE_FIELD( CRpg, m_cActiveRockets, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CRpg, CBasePlayerWeapon ); - -TYPEDESCRIPTION CRpgRocket::m_SaveData[] = -{ - DEFINE_FIELD( CRpgRocket, m_flIgniteTime, FIELD_TIME ), - DEFINE_FIELD( CRpgRocket, m_pLauncher, FIELD_CLASSPTR ), -}; -IMPLEMENT_SAVERESTORE( CRpgRocket, CGrenade ); - -TYPEDESCRIPTION CShotgun::m_SaveData[] = -{ - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - DEFINE_FIELD( CShotgun, m_fInSpecialReload, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flNextReload, FIELD_TIME ), - // DEFINE_FIELD( CShotgun, m_iShell, FIELD_INTEGER ), - DEFINE_FIELD( CShotgun, m_flPumpTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CShotgun, CBasePlayerWeapon ); - -TYPEDESCRIPTION CGauss::m_SaveData[] = -{ - DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ), -// DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ), -// DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ), - DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ), -}; -IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon ); - -TYPEDESCRIPTION CEgon::m_SaveData[] = -{ -// DEFINE_FIELD( CEgon, m_pBeam, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pNoise, FIELD_CLASSPTR ), -// DEFINE_FIELD( CEgon, m_pSprite, FIELD_CLASSPTR ), - DEFINE_FIELD( CEgon, m_shootTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_fireState, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_fireMode, FIELD_INTEGER ), - DEFINE_FIELD( CEgon, m_shakeTime, FIELD_TIME ), - DEFINE_FIELD( CEgon, m_flAmmoUseTime, FIELD_TIME ), -}; -IMPLEMENT_SAVERESTORE( CEgon, CBasePlayerWeapon ); - -TYPEDESCRIPTION CSatchel::m_SaveData[] = -{ - DEFINE_FIELD( CSatchel, m_chargeReady, FIELD_INTEGER ), -}; -IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon ); - diff --git a/sdk/dlls/weapons.h b/sdk/dlls/weapons.h deleted file mode 100644 index 5b3dedb..0000000 --- a/sdk/dlls/weapons.h +++ /dev/null @@ -1,1021 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef WEAPONS_H -#define WEAPONS_H - -#include "effects.h" - -class CBasePlayer; -extern int gmsgWeapPickup; - -void DeactivateSatchels( CBasePlayer *pOwner ); - -// Contact Grenade / Timed grenade / Satchel Charge -class CGrenade : public CBaseMonster -{ -public: - void Spawn( void ); - - typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; - - static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ); - static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); - static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); - - void Explode( Vector vecSrc, Vector vecAim ); - void Explode( TraceResult *pTrace, int bitsDamageType ); - void EXPORT Smoke( void ); - - void EXPORT BounceTouch( CBaseEntity *pOther ); - void EXPORT SlideTouch( CBaseEntity *pOther ); - void EXPORT ExplodeTouch( CBaseEntity *pOther ); - void EXPORT DangerSoundThink( void ); - void EXPORT PreDetonate( void ); - void EXPORT Detonate( void ); - void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - void EXPORT TumbleThink( void ); - - virtual void BounceSound( void ); - virtual int BloodColor( void ) { return DONT_BLEED; } - virtual void Killed( entvars_t *pevAttacker, int iGib ); - - BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. -}; - - -// constant items -#define ITEM_HEALTHKIT 1 -#define ITEM_ANTIDOTE 2 -#define ITEM_SECURITY 3 -#define ITEM_BATTERY 4 - -#define WEAPON_NONE 0 -#define WEAPON_CROWBAR 1 -#define WEAPON_GLOCK 2 -#define WEAPON_PYTHON 3 -#define WEAPON_MP5 4 -#define WEAPON_CHAINGUN 5 -#define WEAPON_CROSSBOW 6 -#define WEAPON_SHOTGUN 7 -#define WEAPON_RPG 8 -#define WEAPON_GAUSS 9 -#define WEAPON_EGON 10 -#define WEAPON_HORNETGUN 11 -#define WEAPON_HANDGRENADE 12 -#define WEAPON_TRIPMINE 13 -#define WEAPON_SATCHEL 14 -#define WEAPON_SNARK 15 - -#define WEAPON_ALLWEAPONS (~(1<absmin = pev->origin + Vector(-16, -16, -5); - pev->absmax = pev->origin + Vector(16, 16, 28); - } - - void PrimaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - - virtual BOOL UseDecrement( void ) - { -#if defined( CLIENT_WEAPONS ) - return TRUE; -#else - return FALSE; -#endif - } - -private: - unsigned short m_usTripFire; - -}; - -class CSqueak : public CBasePlayerWeapon -{ -public: - void Spawn( void ); - void Precache( void ); - int iItemSlot( void ) { return 5; } - int GetItemInfo(ItemInfo *p); - - void PrimaryAttack( void ); - void SecondaryAttack( void ); - BOOL Deploy( void ); - void Holster( int skiplocal = 0 ); - void WeaponIdle( void ); - int m_fJustThrown; - - virtual BOOL UseDecrement( void ) - { -#if defined( CLIENT_WEAPONS ) - return TRUE; -#else - return FALSE; -#endif - } - -private: - unsigned short m_usSnarkFire; -}; - - -#endif // WEAPONS_H diff --git a/sdk/dlls/world.cpp b/sdk/dlls/world.cpp deleted file mode 100644 index 2d91657..0000000 --- a/sdk/dlls/world.cpp +++ /dev/null @@ -1,742 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -/* - -===== world.cpp ======================================================== - - precaches and defs for entities and other data that must always be available. - -*/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "nodes.h" -#include "soundent.h" -#include "client.h" -#include "decals.h" -#include "skill.h" -#include "effects.h" -#include "player.h" -#include "weapons.h" -#include "gamerules.h" -#include "teamplay_gamerules.h" - -extern CGraph WorldGraph; -extern CSoundEnt *pSoundEnt; - -extern CBaseEntity *g_pLastSpawn; -DLL_GLOBAL edict_t *g_pBodyQueueHead; -CGlobalState gGlobalState; -extern DLL_GLOBAL int gDisplayTitle; - -extern void W_Precache(void); - -// -// This must match the list in util.h -// -DLL_DECALLIST gDecals[] = { - { "{shot1", 0 }, // DECAL_GUNSHOT1 - { "{shot2", 0 }, // DECAL_GUNSHOT2 - { "{shot3",0 }, // DECAL_GUNSHOT3 - { "{shot4", 0 }, // DECAL_GUNSHOT4 - { "{shot5", 0 }, // DECAL_GUNSHOT5 - { "{lambda01", 0 }, // DECAL_LAMBDA1 - { "{lambda02", 0 }, // DECAL_LAMBDA2 - { "{lambda03", 0 }, // DECAL_LAMBDA3 - { "{lambda04", 0 }, // DECAL_LAMBDA4 - { "{lambda05", 0 }, // DECAL_LAMBDA5 - { "{lambda06", 0 }, // DECAL_LAMBDA6 - { "{scorch1", 0 }, // DECAL_SCORCH1 - { "{scorch2", 0 }, // DECAL_SCORCH2 - { "{blood1", 0 }, // DECAL_BLOOD1 - { "{blood2", 0 }, // DECAL_BLOOD2 - { "{blood3", 0 }, // DECAL_BLOOD3 - { "{blood4", 0 }, // DECAL_BLOOD4 - { "{blood5", 0 }, // DECAL_BLOOD5 - { "{blood6", 0 }, // DECAL_BLOOD6 - { "{yblood1", 0 }, // DECAL_YBLOOD1 - { "{yblood2", 0 }, // DECAL_YBLOOD2 - { "{yblood3", 0 }, // DECAL_YBLOOD3 - { "{yblood4", 0 }, // DECAL_YBLOOD4 - { "{yblood5", 0 }, // DECAL_YBLOOD5 - { "{yblood6", 0 }, // DECAL_YBLOOD6 - { "{break1", 0 }, // DECAL_GLASSBREAK1 - { "{break2", 0 }, // DECAL_GLASSBREAK2 - { "{break3", 0 }, // DECAL_GLASSBREAK3 - { "{bigshot1", 0 }, // DECAL_BIGSHOT1 - { "{bigshot2", 0 }, // DECAL_BIGSHOT2 - { "{bigshot3", 0 }, // DECAL_BIGSHOT3 - { "{bigshot4", 0 }, // DECAL_BIGSHOT4 - { "{bigshot5", 0 }, // DECAL_BIGSHOT5 - { "{spit1", 0 }, // DECAL_SPIT1 - { "{spit2", 0 }, // DECAL_SPIT2 - { "{bproof1", 0 }, // DECAL_BPROOF1 - { "{gargstomp", 0 }, // DECAL_GARGSTOMP1, // Gargantua stomp crack - { "{smscorch1", 0 }, // DECAL_SMALLSCORCH1, // Small scorch mark - { "{smscorch2", 0 }, // DECAL_SMALLSCORCH2, // Small scorch mark - { "{smscorch3", 0 }, // DECAL_SMALLSCORCH3, // Small scorch mark - { "{mommablob", 0 }, // DECAL_MOMMABIRTH // BM Birth spray - { "{mommablob", 0 }, // DECAL_MOMMASPLAT // BM Mortar spray?? need decal -}; - -/* -============================================================================== - -BODY QUE - -============================================================================== -*/ - -#define SF_DECAL_NOTINDEATHMATCH 2048 - -class CDecal : public CBaseEntity -{ -public: - void Spawn( void ); - void KeyValue( KeyValueData *pkvd ); - void EXPORT StaticDecal( void ); - void EXPORT TriggerDecal( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); -}; - -LINK_ENTITY_TO_CLASS( infodecal, CDecal ); - -// UNDONE: These won't get sent to joining players in multi-player -void CDecal :: Spawn( void ) -{ - if ( pev->skin < 0 || (gpGlobals->deathmatch && FBitSet( pev->spawnflags, SF_DECAL_NOTINDEATHMATCH )) ) - { - REMOVE_ENTITY(ENT(pev)); - return; - } - - if ( FStringNull ( pev->targetname ) ) - { - SetThink( &CDecal::StaticDecal ); - // if there's no targetname, the decal will spray itself on as soon as the world is done spawning. - pev->nextthink = gpGlobals->time; - } - else - { - // if there IS a targetname, the decal sprays itself on when it is triggered. - SetThink ( &CDecal::SUB_DoNothing ); - SetUse( &CDecal::TriggerDecal); - } -} - -void CDecal :: TriggerDecal ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - // this is set up as a USE function for infodecals that have targetnames, so that the - // decal doesn't get applied until it is fired. (usually by a scripted sequence) - TraceResult trace; - int entityIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY); - WRITE_BYTE( TE_BSPDECAL ); - WRITE_COORD( pev->origin.x ); - WRITE_COORD( pev->origin.y ); - WRITE_COORD( pev->origin.z ); - WRITE_SHORT( (int)pev->skin ); - entityIndex = (short)ENTINDEX(trace.pHit); - WRITE_SHORT( entityIndex ); - if ( entityIndex ) - WRITE_SHORT( (int)VARS(trace.pHit)->modelindex ); - MESSAGE_END(); - - SetThink( &CDecal::SUB_Remove ); - pev->nextthink = gpGlobals->time + 0.1; -} - - -void CDecal :: StaticDecal( void ) -{ - TraceResult trace; - int entityIndex, modelIndex; - - UTIL_TraceLine( pev->origin - Vector(5,5,5), pev->origin + Vector(5,5,5), ignore_monsters, ENT(pev), &trace ); - - entityIndex = (short)ENTINDEX(trace.pHit); - if ( entityIndex ) - modelIndex = (int)VARS(trace.pHit)->modelindex; - else - modelIndex = 0; - - g_engfuncs.pfnStaticDecal( pev->origin, (int)pev->skin, entityIndex, modelIndex ); - - SUB_Remove(); -} - - -void CDecal :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "texture")) - { - pev->skin = DECAL_INDEX( pkvd->szValue ); - - // Found - if ( pev->skin >= 0 ) - return; - ALERT( at_console, "Can't find decal %s\n", pkvd->szValue ); - } - else - CBaseEntity::KeyValue( pkvd ); -} - - -// Body queue class here.... It's really just CBaseEntity -class CCorpse : public CBaseEntity -{ - virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } -}; - -LINK_ENTITY_TO_CLASS( bodyque, CCorpse ); - -static void InitBodyQue(void) -{ - string_t istrClassname = MAKE_STRING("bodyque"); - - g_pBodyQueueHead = CREATE_NAMED_ENTITY( istrClassname ); - entvars_t *pev = VARS(g_pBodyQueueHead); - - // Reserve 3 more slots for dead bodies - for ( int i = 0; i < 3; i++ ) - { - pev->owner = CREATE_NAMED_ENTITY( istrClassname ); - pev = VARS(pev->owner); - } - - pev->owner = g_pBodyQueueHead; -} - - -// -// make a body que entry for the given ent so the ent can be respawned elsewhere -// -// GLOBALS ASSUMED SET: g_eoBodyQueueHead -// -void CopyToBodyQue(entvars_t *pev) -{ - if (pev->effects & EF_NODRAW) - return; - - entvars_t *pevHead = VARS(g_pBodyQueueHead); - - pevHead->angles = pev->angles; - pevHead->model = pev->model; - pevHead->modelindex = pev->modelindex; - pevHead->frame = pev->frame; - pevHead->colormap = pev->colormap; - pevHead->movetype = MOVETYPE_TOSS; - pevHead->velocity = pev->velocity; - pevHead->flags = 0; - pevHead->deadflag = pev->deadflag; - pevHead->renderfx = kRenderFxDeadPlayer; - pevHead->renderamt = ENTINDEX( ENT( pev ) ); - - pevHead->effects = pev->effects | EF_NOINTERP; - //pevHead->goalstarttime = pev->goalstarttime; - //pevHead->goalframe = pev->goalframe; - //pevHead->goalendtime = pev->goalendtime ; - - pevHead->sequence = pev->sequence; - pevHead->animtime = pev->animtime; - - UTIL_SetOrigin(pevHead, pev->origin); - UTIL_SetSize(pevHead, pev->mins, pev->maxs); - g_pBodyQueueHead = pevHead->owner; -} - - -CGlobalState::CGlobalState( void ) -{ - Reset(); -} - -void CGlobalState::Reset( void ) -{ - m_pList = NULL; - m_listCount = 0; -} - -globalentity_t *CGlobalState :: Find( string_t globalname ) -{ - if ( !globalname ) - return NULL; - - globalentity_t *pTest; - const char *pEntityName = STRING(globalname); - - - pTest = m_pList; - while ( pTest ) - { - if ( FStrEq( pEntityName, pTest->name ) ) - break; - - pTest = pTest->pNext; - } - - return pTest; -} - - -// This is available all the time now on impulse 104, remove later -//#ifdef _DEBUG -void CGlobalState :: DumpGlobals( void ) -{ - static const char *estates[] = { "Off", "On", "Dead" }; - globalentity_t *pTest; - - ALERT( at_console, "-- Globals --\n" ); - pTest = m_pList; - while ( pTest ) - { - ALERT( at_console, "%s: %s (%s)\n", pTest->name, pTest->levelName, estates[pTest->state] ); - pTest = pTest->pNext; - } -} -//#endif - - -void CGlobalState :: EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ) -{ - ASSERT( !Find(globalname) ); - - globalentity_t *pNewEntity = (globalentity_t *)calloc( sizeof( globalentity_t ), 1 ); - ASSERT( pNewEntity != NULL ); - pNewEntity->pNext = m_pList; - m_pList = pNewEntity; - strcpy( pNewEntity->name, STRING( globalname ) ); - strcpy( pNewEntity->levelName, STRING(mapName) ); - pNewEntity->state = state; - m_listCount++; -} - - -void CGlobalState :: EntitySetState( string_t globalname, GLOBALESTATE state ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - pEnt->state = state; -} - - -const globalentity_t *CGlobalState :: EntityFromTable( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - - return pEnt; -} - - -GLOBALESTATE CGlobalState :: EntityGetState( string_t globalname ) -{ - globalentity_t *pEnt = Find( globalname ); - if ( pEnt ) - return pEnt->state; - - return GLOBAL_OFF; -} - - -// Global Savedata for Delay -TYPEDESCRIPTION CGlobalState::m_SaveData[] = -{ - DEFINE_FIELD( CGlobalState, m_listCount, FIELD_INTEGER ), -}; - -// Global Savedata for Delay -TYPEDESCRIPTION gGlobalEntitySaveData[] = -{ - DEFINE_ARRAY( globalentity_t, name, FIELD_CHARACTER, 64 ), - DEFINE_ARRAY( globalentity_t, levelName, FIELD_CHARACTER, 32 ), - DEFINE_FIELD( globalentity_t, state, FIELD_INTEGER ), -}; - - -int CGlobalState::Save( CSave &save ) -{ - int i; - globalentity_t *pEntity; - - if ( !save.WriteFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - pEntity = m_pList; - for ( i = 0; i < m_listCount && pEntity; i++ ) - { - if ( !save.WriteFields( "GENT", pEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - - pEntity = pEntity->pNext; - } - - return 1; -} - -int CGlobalState::Restore( CRestore &restore ) -{ - int i, listCount; - globalentity_t tmpEntity; - - - ClearStates(); - if ( !restore.ReadFields( "GLOBAL", this, m_SaveData, ARRAYSIZE(m_SaveData) ) ) - return 0; - - listCount = m_listCount; // Get new list count - m_listCount = 0; // Clear loaded data - - for ( i = 0; i < listCount; i++ ) - { - if ( !restore.ReadFields( "GENT", &tmpEntity, gGlobalEntitySaveData, ARRAYSIZE(gGlobalEntitySaveData) ) ) - return 0; - EntityAdd( MAKE_STRING(tmpEntity.name), MAKE_STRING(tmpEntity.levelName), tmpEntity.state ); - } - return 1; -} - -void CGlobalState::EntityUpdate( string_t globalname, string_t mapname ) -{ - globalentity_t *pEnt = Find( globalname ); - - if ( pEnt ) - strcpy( pEnt->levelName, STRING(mapname) ); -} - - -void CGlobalState::ClearStates( void ) -{ - globalentity_t *pFree = m_pList; - while ( pFree ) - { - globalentity_t *pNext = pFree->pNext; - free( pFree ); - pFree = pNext; - } - Reset(); -} - - -void SaveGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CSave saveHelper( pSaveData ); - gGlobalState.Save( saveHelper ); -} - - -void RestoreGlobalState( SAVERESTOREDATA *pSaveData ) -{ - CRestore restoreHelper( pSaveData ); - gGlobalState.Restore( restoreHelper ); -} - - -void ResetGlobalState( void ) -{ - gGlobalState.ClearStates(); - gInitHUD = TRUE; // Init the HUD on a new game / load game -} - -// moved CWorld class definition to cbase.h -//======================= -// CWorld -// -// This spawns first when each level begins. -//======================= - -LINK_ENTITY_TO_CLASS( worldspawn, CWorld ); - -#define SF_WORLD_DARK 0x0001 // Fade from black at startup -#define SF_WORLD_TITLE 0x0002 // Display game title at startup -#define SF_WORLD_FORCETEAM 0x0004 // Force teams - -extern DLL_GLOBAL BOOL g_fGameOver; -float g_flWeaponCheat; - -void CWorld :: Spawn( void ) -{ - g_fGameOver = FALSE; - Precache( ); - g_flWeaponCheat = CVAR_GET_FLOAT( "sv_cheats" ); // Is the impulse 101 command allowed? -} - -void CWorld :: Precache( void ) -{ - g_pLastSpawn = NULL; - -#if 1 - CVAR_SET_STRING("sv_gravity", "800"); // 67ft/sec - CVAR_SET_STRING("sv_stepsize", "18"); -#else - CVAR_SET_STRING("sv_gravity", "384"); // 32ft/sec - CVAR_SET_STRING("sv_stepsize", "24"); -#endif - - CVAR_SET_STRING("room_type", "0");// clear DSP - - // Set up game rules - if (g_pGameRules) - { - delete g_pGameRules; - } - - g_pGameRules = InstallGameRules( ); - - //!!!UNDONE why is there so much Spawn code in the Precache function? I'll just keep it here - - ///!!!LATER - do we want a sound ent in deathmatch? (sjb) - //pSoundEnt = CBaseEntity::Create( "soundent", g_vecZero, g_vecZero, edict() ); - pSoundEnt = GetClassPtr( ( CSoundEnt *)NULL ); - pSoundEnt->Spawn(); - - if ( !pSoundEnt ) - { - ALERT ( at_console, "**COULD NOT CREATE SOUNDENT**\n" ); - } - - InitBodyQue(); - -// init sentence group playback stuff from sentences.txt. -// ok to call this multiple times, calls after first are ignored. - - SENTENCEG_Init(); - -// init texture type array from materials.txt - - TEXTURETYPE_Init(); - - -// the area based ambient sounds MUST be the first precache_sounds - -// player precaches - W_Precache (); // get weapon precaches - - ClientPrecache(); - -// sounds used from C physics code - PRECACHE_SOUND("common/null.wav"); // clears sound channels - - PRECACHE_SOUND( "items/suitchargeok1.wav" );//!!! temporary sound for respawning weapons. - PRECACHE_SOUND( "items/gunpickup2.wav" );// player picks up a gun. - - PRECACHE_SOUND( "common/bodydrop3.wav" );// dead bodies hitting the ground (animation events) - PRECACHE_SOUND( "common/bodydrop4.wav" ); - - g_Language = (int)CVAR_GET_FLOAT( "sv_language" ); - if ( g_Language == LANGUAGE_GERMAN ) - { - PRECACHE_MODEL( "models/germangibs.mdl" ); - } - else - { - PRECACHE_MODEL( "models/hgibs.mdl" ); - PRECACHE_MODEL( "models/agibs.mdl" ); - } - - PRECACHE_SOUND ("weapons/ric1.wav"); - PRECACHE_SOUND ("weapons/ric2.wav"); - PRECACHE_SOUND ("weapons/ric3.wav"); - PRECACHE_SOUND ("weapons/ric4.wav"); - PRECACHE_SOUND ("weapons/ric5.wav"); -// -// Setup light animation tables. 'a' is total darkness, 'z' is maxbright. -// - - // 0 normal - LIGHT_STYLE(0, "m"); - - // 1 FLICKER (first variety) - LIGHT_STYLE(1, "mmnmmommommnonmmonqnmmo"); - - // 2 SLOW STRONG PULSE - LIGHT_STYLE(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); - - // 3 CANDLE (first variety) - LIGHT_STYLE(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); - - // 4 FAST STROBE - LIGHT_STYLE(4, "mamamamamama"); - - // 5 GENTLE PULSE 1 - LIGHT_STYLE(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); - - // 6 FLICKER (second variety) - LIGHT_STYLE(6, "nmonqnmomnmomomno"); - - // 7 CANDLE (second variety) - LIGHT_STYLE(7, "mmmaaaabcdefgmmmmaaaammmaamm"); - - // 8 CANDLE (third variety) - LIGHT_STYLE(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); - - // 9 SLOW STROBE (fourth variety) - LIGHT_STYLE(9, "aaaaaaaazzzzzzzz"); - - // 10 FLUORESCENT FLICKER - LIGHT_STYLE(10, "mmamammmmammamamaaamammma"); - - // 11 SLOW PULSE NOT FADE TO BLACK - LIGHT_STYLE(11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); - - // 12 UNDERWATER LIGHT MUTATION - // this light only distorts the lightmap - no contribution - // is made to the brightness of affected surfaces - LIGHT_STYLE(12, "mmnnmmnnnmmnn"); - - // styles 32-62 are assigned by the light program for switchable lights - - // 63 testing - LIGHT_STYLE(63, "a"); - - for ( int i = 0; i < static_cast(ARRAYSIZE(gDecals)); i++ ) - gDecals[i].index = DECAL_INDEX( gDecals[i].name ); - -// init the WorldGraph. - WorldGraph.InitGraph(); - -// make sure the .NOD file is newer than the .BSP file. - if ( !WorldGraph.CheckNODFile ( ( char * )STRING( gpGlobals->mapname ) ) ) - {// NOD file is not present, or is older than the BSP file. - WorldGraph.AllocNodes (); - } - else - {// Load the node graph for this level - if ( !WorldGraph.FLoadGraph ( (char *)STRING( gpGlobals->mapname ) ) ) - {// couldn't load, so alloc and prepare to build a graph. - ALERT ( at_console, "*Error opening .NOD file\n" ); - WorldGraph.AllocNodes (); - } - else - { - ALERT ( at_console, "\n*Graph Loaded!\n" ); - } - } - - if ( pev->speed > 0 ) - CVAR_SET_FLOAT( "sv_zmax", pev->speed ); - else - CVAR_SET_FLOAT( "sv_zmax", 4096 ); - - if ( pev->netname ) - { - ALERT( at_aiconsole, "Chapter title: %s\n", STRING(pev->netname) ); - CBaseEntity *pEntity = CBaseEntity::Create( "env_message", g_vecZero, g_vecZero, NULL ); - if ( pEntity ) - { - pEntity->SetThink( &CBaseEntity::SUB_CallUseToggle ); - pEntity->pev->message = pev->netname; - pev->netname = 0; - pEntity->pev->nextthink = gpGlobals->time + 0.3; - pEntity->pev->spawnflags = SF_MESSAGE_ONCE; - } - } - - if ( pev->spawnflags & SF_WORLD_DARK ) - CVAR_SET_FLOAT( "v_dark", 1.0 ); - else - CVAR_SET_FLOAT( "v_dark", 0.0 ); - - if ( pev->spawnflags & SF_WORLD_TITLE ) - gDisplayTitle = TRUE; // display the game title if this key is set - else - gDisplayTitle = FALSE; - - if ( pev->spawnflags & SF_WORLD_FORCETEAM ) - { - CVAR_SET_FLOAT( "mp_defaultteam", 1 ); - } - else - { - CVAR_SET_FLOAT( "mp_defaultteam", 0 ); - } -} - - -// -// Just to ignore the "wad" field. -// -void CWorld :: KeyValue( KeyValueData *pkvd ) -{ - if ( FStrEq(pkvd->szKeyName, "skyname") ) - { - // Sent over net now. - CVAR_SET_STRING( "sv_skyname", pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "sounds") ) - { - gpGlobals->cdAudioTrack = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "WaveHeight") ) - { - // Sent over net now. - pev->scale = atof(pkvd->szValue) * (1.0/8.0); - pkvd->fHandled = TRUE; - CVAR_SET_FLOAT( "sv_wateramp", pev->scale ); - } - else if ( FStrEq(pkvd->szKeyName, "MaxRange") ) - { - pev->speed = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "chaptertitle") ) - { - pev->netname = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "startdark") ) - { - // UNDONE: This is a gross hack!!! The CVAR is NOT sent over the client/sever link - // but it will work for single player - int flag = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - if ( flag ) - pev->spawnflags |= SF_WORLD_DARK; - } - else if ( FStrEq(pkvd->szKeyName, "newunit") ) - { - // Single player only. Clear save directory if set - if ( atoi(pkvd->szValue) ) - CVAR_SET_FLOAT( "sv_newunit", 1 ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "gametitle") ) - { - if ( atoi(pkvd->szValue) ) - pev->spawnflags |= SF_WORLD_TITLE; - - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "mapteams") ) - { - pev->team = ALLOC_STRING( pkvd->szValue ); - pkvd->fHandled = TRUE; - } - else if ( FStrEq(pkvd->szKeyName, "defaultteam") ) - { - if ( atoi(pkvd->szValue) ) - { - pev->spawnflags |= SF_WORLD_FORCETEAM; - } - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} diff --git a/sdk/dlls/wpn_shared/hl_wpn_glock.cpp b/sdk/dlls/wpn_shared/hl_wpn_glock.cpp deleted file mode 100644 index 0798fcb..0000000 --- a/sdk/dlls/wpn_shared/hl_wpn_glock.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "weapons.h" -#include "nodes.h" -#include "player.h" - -enum glock_e { - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); -LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); - - -void CGlock::Spawn( ) -{ - pev->classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names - Precache( ); - m_iId = WEAPON_GLOCK; - SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); - - m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; - - FallInit();// get ready to fall down. -} - - -void CGlock::Precache( void ) -{ - PRECACHE_MODEL("models/v_9mmhandgun.mdl"); - PRECACHE_MODEL("models/w_9mmhandgun.mdl"); - PRECACHE_MODEL("models/p_9mmhandgun.mdl"); - - m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - - PRECACHE_SOUND("items/9mmclip1.wav"); - PRECACHE_SOUND("items/9mmclip2.wav"); - - PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun - PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun - - m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); - m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); -} - -int CGlock::GetItemInfo(ItemInfo *p) -{ - p->pszName = STRING(pev->classname); - p->pszAmmo1 = "9mm"; - p->iMaxAmmo1 = _9MM_MAX_CARRY; - p->pszAmmo2 = NULL; - p->iMaxAmmo2 = -1; - p->iMaxClip = GLOCK_MAX_CLIP; - p->iSlot = 1; - p->iPosition = 0; - p->iFlags = 0; - p->iId = m_iId = WEAPON_GLOCK; - p->iWeight = GLOCK_WEIGHT; - - return 1; -} - -BOOL CGlock::Deploy( ) -{ - // pev->body = 1; - return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); -} - -void CGlock::SecondaryAttack( void ) -{ - GlockFire( 0.1, 0.2, FALSE ); -} - -void CGlock::PrimaryAttack( void ) -{ - GlockFire( 0.01, 0.3, TRUE ); -} - -void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) -{ - if (m_iClip <= 0) - { - if (m_fFireOnEmpty) - { - PlayEmptySound(); - m_flNextPrimaryAttack = GetNextAttackDelay(0.2); - } - - return; - } - - m_iClip--; - - m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - - int flags; - -#if defined( CLIENT_WEAPONS ) - flags = FEV_NOTHOST; -#else - flags = 0; -#endif - - // player "shoot" animation - m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - - // silenced - if (pev->body == 1) - { - m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; - } - else - { - // non-silenced - m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; - m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; - } - - Vector vecSrc = m_pPlayer->GetGunPosition( ); - Vector vecAiming; - - if ( fUseAutoAim ) - { - vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - } - else - { - vecAiming = gpGlobals->v_forward; - } - - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = GetNextAttackDelay(flCycleTime); - - if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) - // HEV suit - indicate out of ammo condition - m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); -} - - -void CGlock::Reload( void ) -{ - if ( m_pPlayer->ammo_9mm <= 0 ) - return; - - int iResult; - - if (m_iClip == 0) - iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); - else - iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); - - if (iResult) - { - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); - } -} - - - -void CGlock::WeaponIdle( void ) -{ - ResetEmptySound( ); - - m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - - if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) - return; - - // only idle if the slid isn't back - if (m_iClip != 0) - { - int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); - - if (flRand <= 0.3 + 0 * 0.75) - { - iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; - } - else if (flRand <= 0.6 + 0 * 0.875) - { - iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; - } - else - { - iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; - } - SendWeaponAnim( iAnim, 1 ); - } -} - - - - - - - - -class CGlockAmmo : public CBasePlayerAmmo -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); - CBasePlayerAmmo::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/w_9mmclip.mdl"); - PRECACHE_SOUND("items/9mmclip1.wav"); - } - BOOL AddAmmo( CBaseEntity *pOther ) - { - if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) - { - EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); -LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); - - - - - - - - - - - - - - - diff --git a/sdk/dlls/wxdebug.h b/sdk/dlls/wxdebug.h deleted file mode 100644 index 026039a..0000000 --- a/sdk/dlls/wxdebug.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef __WXDEBUG__ -#define __WXDEBUG__ - -// This library provides fairly straight forward debugging functionality, this -// is split into two main sections. The first is assertion handling, there are -// three types of assertions provided here. The most commonly used one is the -// ASSERT(condition) macro which will pop up a message box including the file -// and line number if the condition evaluates to FALSE. Then there is the -// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will -// still be executed in NON debug builds. The final type of assertion is the -// KASSERT macro which is more suitable for pure (perhaps kernel) filters as -// the condition is printed onto the debugger rather than in a message box. -// -// The other part of the debug module facilties is general purpose logging. -// This is accessed by calling DbgLog(). The function takes a type and level -// field which define the type of informational string you are presenting and -// it's relative importance. The type field can be a combination (one or more) -// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level -// is a DWORD value where zero defines highest important. Use of zero as the -// debug logging level is to be encouraged ONLY for major errors or events as -// they will ALWAYS be displayed on the debugger. Other debug output has it's -// level matched against the current debug output level stored in the registry -// for this module and if less than the current setting it will be displayed. -// -// Each module or executable has it's own debug output level for each of the -// five types. These are read in when the DbgInitialise function is called -// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL -// is loaded, executables must call it explicitely with the module instance -// handle given to them through the WINMAIN entry point. An executable must -// also call DbgTerminate when they have finished to clean up the resources -// the debug library uses, once again this is done automatically for DLLs - -// These are the five different categories of logging information - -#ifdef _DEBUG - - -enum -{ - LOG_TRACE = 0x00000001, // General tracing - LOG_ENTRY = 0x00000002, // Function entry logging - LOG_EXIT = 0x00000004, // Function exit logging - LOG_MEMORY = 0x00000008, // Memory alloc/free debugging - LOG_ERROR = 0x00000010, // Error notification - LOG_UNUSED0 = 0x00000020, // reserved - LOG_UNUSED1 = 0x00000040, // reserved - LOG_UNUSED2 = 0x00000080, // reserved - LOG_CHUM = 0x00000100, // Chumtoad debugging - LOG_LEECH = 0x00000200, // Leech debugging - LOG_ICHTHYOSAUR = 0x00000400, // Ichthyosaur debugging -}; - - -// These are public but should be called only by the DLLMain function -void WINAPI DbgInitialise(HINSTANCE hInst); -void WINAPI DbgTerminate(); -// These are public but should be called by macro only -void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); -void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); -void WINAPI DbgOutString(LPCTSTR psz); - - -// These are the macros that should be used in code. - -#define DBGASSERT(_x_) \ - if (!(_x_)) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGBREAK(_x_) \ - DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) - -#define DBGASSERTEXECUTE(_x_) DBGASSERT(_x_) - -#define DBGLOG(_x_) DbgLogInfo _x_ - -#define DBGOUT(_x_) DbgOutString(_x_) - -#define ValidateReadPtr(p,cb) \ - {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid read pointer");} - -#define ValidateWritePtr(p,cb) \ - {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ - DBGBREAK("Invalid write pointer");} - -#define ValidateReadWritePtr(p,cb) \ - {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} - -#define ValidateStringPtr(p) \ - {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid string pointer");} - -#define ValidateStringPtrA(p) \ - {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid ANSII string pointer");} - -#define ValidateStringPtrW(p) \ - {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ - DBGBREAK("Invalid UNICODE string pointer");} - -#else // !_DEBUG - -// Retail builds make public debug functions inert - WARNING the source -// files do not define or build any of the entry points in debug builds -// (public entry points compile to nothing) so if you go trying to call -// any of the private entry points in your source they won't compile - -#define DBGASSERT(_x_) -#define DBGBREAK(_x_) -#define DBGASSERTEXECUTE(_x_) _x_ -#define DBGLOG(_x_) -#define DBGOUT(_x_) -#define ValidateReadPtr(p,cb) -#define ValidateWritePtr(p,cb) -#define ValidateReadWritePtr(p,cb) -#define ValidateStringPtr(p) -#define ValidateStringPtrA(p) -#define ValidateStringPtrW(p) - -#endif // !_DEBUG - - -#ifndef REMIND - // REMIND macro - generates warning as reminder to complete coding - // (eg) usage: - // - // #pragma message (REMIND("Add automation support")) - - - #define REMINDQUOTE(x) #x - #define REMINDQQUOTE(y) REMINDQUOTE(y) - #define REMIND(str) __FILE__ "(" REMINDQQUOTE(__LINE__) ") : " str -#endif - -#endif // __WXDEBUG__ - - diff --git a/sdk/dlls/xen.cpp b/sdk/dlls/xen.cpp deleted file mode 100644 index ff35cb8..0000000 --- a/sdk/dlls/xen.cpp +++ /dev/null @@ -1,584 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "animation.h" -#include "effects.h" - - -#define XEN_PLANT_GLOW_SPRITE "sprites/flare3.spr" -#define XEN_PLANT_HIDE_TIME 5 - - -class CActAnimating : public CBaseAnimating -{ -public: - void SetActivity( Activity act ); - inline Activity GetActivity( void ) { return m_Activity; } - - virtual int ObjectCaps( void ) { return CBaseAnimating :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - Activity m_Activity; -}; - -TYPEDESCRIPTION CActAnimating::m_SaveData[] = -{ - DEFINE_FIELD( CActAnimating, m_Activity, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CActAnimating, CBaseAnimating ); - -void CActAnimating :: SetActivity( Activity act ) -{ - int sequence = LookupActivity( act ); - if ( sequence != ACTIVITY_NOT_AVAILABLE ) - { - pev->sequence = sequence; - m_Activity = act; - pev->frame = 0; - ResetSequenceInfo( ); - } -} - - - - -class CXenPLight : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - - void LightOn( void ); - void LightOff( void ); - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - -private: - CSprite *m_pGlow; -}; - -LINK_ENTITY_TO_CLASS( xen_plantlight, CXenPLight ); - -TYPEDESCRIPTION CXenPLight::m_SaveData[] = -{ - DEFINE_FIELD( CXenPLight, m_pGlow, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CXenPLight, CActAnimating ); - -void CXenPLight :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), "models/light.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_TRIGGER; - - UTIL_SetSize( pev, Vector(-80,-80,0), Vector(80,80,32)); - SetActivity( ACT_IDLE ); - pev->nextthink = gpGlobals->time + 0.1; - pev->frame = RANDOM_FLOAT(0,255); - - m_pGlow = CSprite::SpriteCreate( XEN_PLANT_GLOW_SPRITE, pev->origin + Vector(0,0,(pev->mins.z+pev->maxs.z)*0.5), FALSE ); - m_pGlow->SetTransparency( kRenderGlow, static_cast(pev->rendercolor.x), static_cast(pev->rendercolor.y), static_cast(pev->rendercolor.z), static_cast(pev->renderamt), static_cast(pev->renderfx) ); - m_pGlow->SetAttachment( edict(), 1 ); -} - - -void CXenPLight :: Precache( void ) -{ - PRECACHE_MODEL( "models/light.mdl" ); - PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); -} - - -void CXenPLight :: Think( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - - switch( GetActivity() ) - { - case ACT_CROUCH: - if ( m_fSequenceFinished ) - { - SetActivity( ACT_CROUCHIDLE ); - LightOff(); - } - break; - - case ACT_CROUCHIDLE: - if ( gpGlobals->time > pev->dmgtime ) - { - SetActivity( ACT_STAND ); - LightOn(); - } - break; - - case ACT_STAND: - if ( m_fSequenceFinished ) - SetActivity( ACT_IDLE ); - break; - - case ACT_IDLE: - default: - break; - } -} - - -void CXenPLight :: Touch( CBaseEntity *pOther ) -{ - if ( pOther->IsPlayer() ) - { - pev->dmgtime = gpGlobals->time + XEN_PLANT_HIDE_TIME; - if ( GetActivity() == ACT_IDLE || GetActivity() == ACT_STAND ) - { - SetActivity( ACT_CROUCH ); - } - } -} - - -void CXenPLight :: LightOn( void ) -{ - SUB_UseTargets( this, USE_ON, 0 ); - if ( m_pGlow ) - m_pGlow->pev->effects &= ~EF_NODRAW; -} - - -void CXenPLight :: LightOff( void ) -{ - SUB_UseTargets( this, USE_OFF, 0 ); - if ( m_pGlow ) - m_pGlow->pev->effects |= EF_NODRAW; -} - - - -class CXenHair : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Think( void ); -}; - -LINK_ENTITY_TO_CLASS( xen_hair, CXenHair ); - -#define SF_HAIR_SYNC 0x0001 - -void CXenHair::Spawn( void ) -{ - Precache(); - SET_MODEL( edict(), "models/hair.mdl" ); - UTIL_SetSize( pev, Vector(-4,-4,0), Vector(4,4,32)); - pev->sequence = 0; - - if ( !(pev->spawnflags & SF_HAIR_SYNC) ) - { - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - } - ResetSequenceInfo( ); - - pev->solid = SOLID_NOT; - pev->movetype = MOVETYPE_NONE; - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit -} - - -void CXenHair::Think( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.5; -} - - -void CXenHair::Precache( void ) -{ - PRECACHE_MODEL( "models/hair.mdl" ); -} - - -class CXenTreeTrigger : public CBaseEntity -{ -public: - void Touch( CBaseEntity *pOther ); - static CXenTreeTrigger *TriggerCreate( edict_t *pOwner, const Vector &position ); -}; -LINK_ENTITY_TO_CLASS( xen_ttrigger, CXenTreeTrigger ); - -CXenTreeTrigger *CXenTreeTrigger :: TriggerCreate( edict_t *pOwner, const Vector &position ) -{ - CXenTreeTrigger *pTrigger = GetClassPtr( (CXenTreeTrigger *)NULL ); - pTrigger->pev->origin = position; - pTrigger->pev->classname = MAKE_STRING("xen_ttrigger"); - pTrigger->pev->solid = SOLID_TRIGGER; - pTrigger->pev->movetype = MOVETYPE_NONE; - pTrigger->pev->owner = pOwner; - - return pTrigger; -} - - -void CXenTreeTrigger::Touch( CBaseEntity *pOther ) -{ - if ( pev->owner ) - { - CBaseEntity *pEntity = CBaseEntity::Instance(pev->owner); - pEntity->Touch( pOther ); - } -} - - -#define TREE_AE_ATTACK 1 - -class CXenTree : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } - void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Attack( void ); - int Classify( void ) { return CLASS_BARNACLE; } - - virtual int Save( CSave &save ); - virtual int Restore( CRestore &restore ); - static TYPEDESCRIPTION m_SaveData[]; - - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - -private: - CXenTreeTrigger *m_pTrigger; -}; - -LINK_ENTITY_TO_CLASS( xen_tree, CXenTree ); - -TYPEDESCRIPTION CXenTree::m_SaveData[] = -{ - DEFINE_FIELD( CXenTree, m_pTrigger, FIELD_CLASSPTR ), -}; - -IMPLEMENT_SAVERESTORE( CXenTree, CActAnimating ); - -void CXenTree :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), "models/tree.mdl" ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - - pev->takedamage = DAMAGE_YES; - - UTIL_SetSize( pev, Vector(-30,-30,0), Vector(30,30,188)); - SetActivity( ACT_IDLE ); - pev->nextthink = gpGlobals->time + 0.1; - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - - Vector triggerPosition; - UTIL_MakeVectorsPrivate( pev->angles, triggerPosition, NULL, NULL ); - triggerPosition = pev->origin + (triggerPosition * 64); - // Create the trigger - m_pTrigger = CXenTreeTrigger::TriggerCreate( edict(), triggerPosition ); - UTIL_SetSize( m_pTrigger->pev, Vector( -24, -24, 0 ), Vector( 24, 24, 128 ) ); -} - -const char *CXenTree::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CXenTree::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -void CXenTree :: Precache( void ) -{ - PRECACHE_MODEL( "models/tree.mdl" ); - PRECACHE_MODEL( XEN_PLANT_GLOW_SPRITE ); - PRECACHE_SOUND_ARRAY( pAttackHitSounds ); - PRECACHE_SOUND_ARRAY( pAttackMissSounds ); -} - - -void CXenTree :: Touch( CBaseEntity *pOther ) -{ - if ( !pOther->IsPlayer() && FClassnameIs( pOther->pev, "monster_bigmomma" ) ) - return; - - Attack(); -} - - -void CXenTree :: Attack( void ) -{ - if ( GetActivity() == ACT_IDLE ) - { - SetActivity( ACT_MELEE_ATTACK1 ); - pev->framerate = RANDOM_FLOAT( 1.0, 1.4 ); - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackMissSounds ); - } -} - - -void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case TREE_AE_ATTACK: - { - CBaseEntity *pList[8]; - BOOL sound = FALSE; - int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT ); - Vector forward; - - UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL ); - - for ( int i = 0; i < count; i++ ) - { - if ( pList[i] != this ) - { - if ( pList[i]->pev->owner != edict() ) - { - sound = TRUE; - pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH ); - pList[i]->pev->punchangle.x = 15; - pList[i]->pev->velocity = pList[i]->pev->velocity + forward * 100; - } - } - } - - if ( sound ) - { - EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds ); - } - } - return; - } - - CActAnimating::HandleAnimEvent( pEvent ); -} - -void CXenTree :: Think( void ) -{ - float flInterval = StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - DispatchAnimEvents( flInterval ); - - switch( GetActivity() ) - { - case ACT_MELEE_ATTACK1: - if ( m_fSequenceFinished ) - { - SetActivity( ACT_IDLE ); - pev->framerate = RANDOM_FLOAT( 0.6, 1.4 ); - } - break; - - default: - case ACT_IDLE: - break; - - } -} - - -// UNDONE: These need to smoke somehow when they take damage -// Touch behavior? -// Cause damage in smoke area - -// -// Spores -// -class CXenSpore : public CActAnimating -{ -public: - void Spawn( void ); - void Precache( void ); - void Touch( CBaseEntity *pOther ); - void Think( void ); - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { Attack(); return 0; } -// void HandleAnimEvent( MonsterEvent_t *pEvent ); - void Attack( void ) {} - - static const char *pModelNames[]; -}; - -class CXenSporeSmall : public CXenSpore -{ - void Spawn( void ); -}; - -class CXenSporeMed : public CXenSpore -{ - void Spawn( void ); -}; - -class CXenSporeLarge : public CXenSpore -{ - void Spawn( void ); - - static const Vector m_hullSizes[]; -}; - -// Fake collision box for big spores -class CXenHull : public CPointEntity -{ -public: - static CXenHull *CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ); - int Classify( void ) { return CLASS_BARNACLE; } -}; - -CXenHull *CXenHull :: CreateHull( CBaseEntity *source, const Vector &mins, const Vector &maxs, const Vector &offset ) -{ - CXenHull *pHull = GetClassPtr( (CXenHull *)NULL ); - - UTIL_SetOrigin( pHull->pev, source->pev->origin + offset ); - SET_MODEL( pHull->edict(), STRING(source->pev->model) ); - pHull->pev->solid = SOLID_BBOX; - pHull->pev->classname = MAKE_STRING("xen_hull"); - pHull->pev->movetype = MOVETYPE_NONE; - pHull->pev->owner = source->edict(); - UTIL_SetSize( pHull->pev, mins, maxs ); - pHull->pev->renderamt = 0; - pHull->pev->rendermode = kRenderTransTexture; - // pHull->pev->effects = EF_NODRAW; - - return pHull; -} - - -LINK_ENTITY_TO_CLASS( xen_spore_small, CXenSporeSmall ); -LINK_ENTITY_TO_CLASS( xen_spore_medium, CXenSporeMed ); -LINK_ENTITY_TO_CLASS( xen_spore_large, CXenSporeLarge ); -LINK_ENTITY_TO_CLASS( xen_hull, CXenHull ); - -void CXenSporeSmall::Spawn( void ) -{ - pev->skin = 0; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-16,-16,0), Vector(16,16,64)); -} -void CXenSporeMed::Spawn( void ) -{ - pev->skin = 1; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-40,-40,0), Vector(40,40,120)); -} - - -// I just eyeballed these -- fill in hulls for the legs -const Vector CXenSporeLarge::m_hullSizes[] = -{ - Vector( 90, -25, 0 ), - Vector( 25, 75, 0 ), - Vector( -15, -100, 0 ), - Vector( -90, -35, 0 ), - Vector( -90, 60, 0 ), -}; - -void CXenSporeLarge::Spawn( void ) -{ - pev->skin = 2; - CXenSpore::Spawn(); - UTIL_SetSize( pev, Vector(-48,-48,110), Vector(48,48,240)); - - Vector forward, right; - - UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL ); - - // Rotate the leg hulls into position - for ( int i = 0; i < static_cast(ARRAYSIZE(m_hullSizes)); i++ ) - CXenHull :: CreateHull( this, Vector(-12, -12, 0 ), Vector( 12, 12, 120 ), (m_hullSizes[i].x * forward) + (m_hullSizes[i].y * right) ); -} - -void CXenSpore :: Spawn( void ) -{ - Precache(); - - SET_MODEL( ENT(pev), pModelNames[pev->skin] ); - pev->movetype = MOVETYPE_NONE; - pev->solid = SOLID_BBOX; - pev->takedamage = DAMAGE_YES; - -// SetActivity( ACT_IDLE ); - pev->sequence = 0; - pev->frame = RANDOM_FLOAT(0,255); - pev->framerate = RANDOM_FLOAT( 0.7, 1.4 ); - ResetSequenceInfo( ); - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.1, 0.4 ); // Load balance these a bit -} - -const char *CXenSpore::pModelNames[] = -{ - "models/fungus(small).mdl", - "models/fungus.mdl", - "models/fungus(large).mdl", -}; - - -void CXenSpore :: Precache( void ) -{ - PRECACHE_MODEL( (char *)pModelNames[pev->skin] ); -} - - -void CXenSpore :: Touch( CBaseEntity *pOther ) -{ -} - - -void CXenSpore :: Think( void ) -{ - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.1; - -#if 0 - DispatchAnimEvents( flInterval ); - - switch( GetActivity() ) - { - default: - case ACT_IDLE: - break; - - } -#endif -} - - diff --git a/sdk/dlls/zombie.cpp b/sdk/dlls/zombie.cpp deleted file mode 100644 index 7b0958b..0000000 --- a/sdk/dlls/zombie.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/*** -* -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* This source code contains proprietary and confidential information of -* Valve LLC and its suppliers. Access to this code is restricted to -* persons who have executed a written SDK license with Valve. Any access, -* use or distribution of this code by or to any unlicensed person is illegal. -* -****/ -//========================================================= -// Zombie -//========================================================= - -// UNDONE: Don't flinch every time you get hit - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" - - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= -#define ZOMBIE_AE_ATTACK_RIGHT 0x01 -#define ZOMBIE_AE_ATTACK_LEFT 0x02 -#define ZOMBIE_AE_ATTACK_BOTH 0x03 - -#define ZOMBIE_FLINCH_DELAY 2 // at most one flinch every n secs - -class CZombie : public CBaseMonster -{ -public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int Classify ( void ); - void HandleAnimEvent( MonsterEvent_t *pEvent ); - int IgnoreConditions ( void ); - - float m_flNextFlinch; - - void PainSound( void ); - void AlertSound( void ); - void IdleSound( void ); - void AttackSound( void ); - - static const char *pAttackSounds[]; - static const char *pIdleSounds[]; - static const char *pAlertSounds[]; - static const char *pPainSounds[]; - static const char *pAttackHitSounds[]; - static const char *pAttackMissSounds[]; - - // No range attacks - BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } - BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } - int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); -}; - -LINK_ENTITY_TO_CLASS( monster_zombie, CZombie ); - -const char *CZombie::pAttackHitSounds[] = -{ - "zombie/claw_strike1.wav", - "zombie/claw_strike2.wav", - "zombie/claw_strike3.wav", -}; - -const char *CZombie::pAttackMissSounds[] = -{ - "zombie/claw_miss1.wav", - "zombie/claw_miss2.wav", -}; - -const char *CZombie::pAttackSounds[] = -{ - "zombie/zo_attack1.wav", - "zombie/zo_attack2.wav", -}; - -const char *CZombie::pIdleSounds[] = -{ - "zombie/zo_idle1.wav", - "zombie/zo_idle2.wav", - "zombie/zo_idle3.wav", - "zombie/zo_idle4.wav", -}; - -const char *CZombie::pAlertSounds[] = -{ - "zombie/zo_alert10.wav", - "zombie/zo_alert20.wav", - "zombie/zo_alert30.wav", -}; - -const char *CZombie::pPainSounds[] = -{ - "zombie/zo_pain1.wav", - "zombie/zo_pain2.wav", -}; - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CZombie :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CZombie :: SetYawSpeed ( void ) -{ - int ys; - - ys = 120; - -#if 0 - switch ( m_Activity ) - { - } -#endif - - pev->yaw_speed = ys; -} - -int CZombie :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) -{ - // Take 30% damage from bullets - if ( bitsDamageType == DMG_BULLET ) - { - Vector vecDir = pev->origin - (pevInflictor->absmin + pevInflictor->absmax) * 0.5; - vecDir = vecDir.Normalize(); - float flForce = DamageForce( flDamage ); - pev->velocity = pev->velocity + vecDir * flForce; - flDamage *= 0.3; - } - - // HACK HACK -- until we fix this. - if ( IsAlive() ) - PainSound(); - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); -} - -void CZombie :: PainSound( void ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - if (RANDOM_LONG(0,5) < 2) - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie :: AlertSound( void ) -{ - int pitch = 95 + RANDOM_LONG(0,9); - - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAlertSounds[ RANDOM_LONG(0,ARRAYSIZE(pAlertSounds)-1) ], 1.0, ATTN_NORM, 0, pitch ); -} - -void CZombie :: IdleSound( void ) -{ - // Play a random idle sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pIdleSounds[ RANDOM_LONG(0,ARRAYSIZE(pIdleSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); -} - -void CZombie :: AttackSound( void ) -{ - // Play a random attack sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_VOICE, pAttackSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); -} - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CZombie :: HandleAnimEvent( MonsterEvent_t *pEvent ) -{ - switch( pEvent->event ) - { - case ZOMBIE_AE_ATTACK_RIGHT: - { - // do stuff for this event. - // ALERT( at_console, "Slash right!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = -18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100; - } - // Play a random attack hit sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else // Play a random attack miss sound - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - case ZOMBIE_AE_ATTACK_LEFT: - { - // do stuff for this event. - // ALERT( at_console, "Slash left!\n" ); - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgOneSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.z = 18; - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - case ZOMBIE_AE_ATTACK_BOTH: - { - // do stuff for this event. - CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.zombieDmgBothSlash, DMG_SLASH ); - if ( pHurt ) - { - if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) ) - { - pHurt->pev->punchangle.x = 5; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -100; - } - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - } - else - EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) ); - - if (RANDOM_LONG(0,1)) - AttackSound(); - } - break; - - default: - CBaseMonster::HandleAnimEvent( pEvent ); - break; - } -} - -//========================================================= -// Spawn -//========================================================= -void CZombie :: Spawn() -{ - Precache( ); - - SET_MODEL(ENT(pev), "models/zombie.mdl"); - UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.zombieHealth; - pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin. - m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - m_afCapability = bits_CAP_DOORS_GROUP; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CZombie :: Precache() -{ - size_t i; - - PRECACHE_MODEL("models/zombie.mdl"); - - for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackHitSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAttackSounds ); i++ ) - PRECACHE_SOUND((char *)pAttackSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pIdleSounds ); i++ ) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pAlertSounds ); i++ ) - PRECACHE_SOUND((char *)pAlertSounds[i]); - - for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ ) - PRECACHE_SOUND((char *)pPainSounds[i]); -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - - - -int CZombie::IgnoreConditions ( void ) -{ - int iIgnore = CBaseMonster::IgnoreConditions(); - - if ((m_Activity == ACT_MELEE_ATTACK1) || (m_Activity == ACT_MELEE_ATTACK1)) - { -#if 0 - if (pev->health < 20) - iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); - else -#endif - if (m_flNextFlinch >= gpGlobals->time) - iIgnore |= (bits_COND_LIGHT_DAMAGE|bits_COND_HEAVY_DAMAGE); - } - - if ((m_Activity == ACT_SMALL_FLINCH) || (m_Activity == ACT_BIG_FLINCH)) - { - if (m_flNextFlinch < gpGlobals->time) - m_flNextFlinch = gpGlobals->time + ZOMBIE_FLINCH_DELAY; - } - - return iIgnore; - -} diff --git a/sdk/engine/APIProxy.h b/sdk/engine/APIProxy.h deleted file mode 100644 index 8fe4574..0000000 --- a/sdk/engine/APIProxy.h +++ /dev/null @@ -1,939 +0,0 @@ -#ifndef __APIPROXY__ -#define __APIPROXY__ - -#include "archtypes.h" // DAL -#include "netadr.h" -#include "Sequence.h" - -#ifndef _WIN32 -#include "enums.h" -#endif - -#define MAX_ALIAS_NAME 32 - -typedef struct cmdalias_s -{ - struct cmdalias_s *next; - char name[MAX_ALIAS_NAME]; - char *value; -} cmdalias_t; - - -// ******************************************************** -// Functions exported by the client .dll -// ******************************************************** - -// Function type declarations for client exports -typedef int (*INITIALIZE_FUNC) ( struct cl_enginefuncs_s*, int ); -typedef void (*HUD_INIT_FUNC) ( void ); -typedef int (*HUD_VIDINIT_FUNC) ( void ); -typedef int (*HUD_REDRAW_FUNC) ( float, int ); -typedef int (*HUD_UPDATECLIENTDATA_FUNC) ( struct client_data_s*, float ); -typedef void (*HUD_RESET_FUNC) ( void ); -typedef void (*HUD_CLIENTMOVE_FUNC)( struct playermove_s *ppmove, qboolean server ); -typedef void (*HUD_CLIENTMOVEINIT_FUNC)( struct playermove_s *ppmove ); -typedef char (*HUD_TEXTURETYPE_FUNC)( char *name ); -typedef void (*HUD_IN_ACTIVATEMOUSE_FUNC) ( void ); -typedef void (*HUD_IN_DEACTIVATEMOUSE_FUNC) ( void ); -typedef void (*HUD_IN_MOUSEEVENT_FUNC) ( int mstate ); -typedef void (*HUD_IN_CLEARSTATES_FUNC) ( void ); -typedef void (*HUD_IN_ACCUMULATE_FUNC ) ( void ); -typedef void (*HUD_CL_CREATEMOVE_FUNC) ( float frametime, struct usercmd_s *cmd, int active ); -typedef int (*HUD_CL_ISTHIRDPERSON_FUNC) ( void ); -typedef void (*HUD_CL_GETCAMERAOFFSETS_FUNC )( float *ofs ); -typedef struct kbutton_s * (*HUD_KB_FIND_FUNC) ( const char *name ); -typedef void ( *HUD_CAMTHINK_FUNC )( void ); -typedef void ( *HUD_CALCREF_FUNC ) ( struct ref_params_s *pparams ); -typedef int ( *HUD_ADDENTITY_FUNC ) ( int type, struct cl_entity_s *ent, const char *modelname ); -typedef void ( *HUD_CREATEENTITIES_FUNC ) ( void ); -typedef void ( *HUD_DRAWNORMALTRIS_FUNC ) ( void ); -typedef void ( *HUD_DRAWTRANSTRIS_FUNC ) ( void ); -typedef void ( *HUD_STUDIOEVENT_FUNC ) ( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); -typedef void ( *HUD_POSTRUNCMD_FUNC ) ( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); -typedef void ( *HUD_SHUTDOWN_FUNC ) ( void ); -typedef void ( *HUD_TXFERLOCALOVERRIDES_FUNC )( struct entity_state_s *state, const struct clientdata_s *client ); -typedef void ( *HUD_PROCESSPLAYERSTATE_FUNC )( struct entity_state_s *dst, const struct entity_state_s *src ); -typedef void ( *HUD_TXFERPREDICTIONDATA_FUNC ) ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); -typedef void ( *HUD_DEMOREAD_FUNC ) ( int size, unsigned char *buffer ); -typedef int ( *HUD_CONNECTIONLESS_FUNC )( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); -typedef int ( *HUD_GETHULLBOUNDS_FUNC ) ( int hullnumber, float *mins, float *maxs ); -typedef void (*HUD_FRAME_FUNC) ( double ); -typedef int (*HUD_KEY_EVENT_FUNC ) ( int eventcode, int keynum, const char *pszCurrentBinding ); -typedef void (*HUD_TEMPENTUPDATE_FUNC) ( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( struct cl_entity_s *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ) ); -typedef struct cl_entity_s *(*HUD_GETUSERENTITY_FUNC ) ( int index ); -typedef void (*HUD_VOICESTATUS_FUNC)(int entindex, qboolean bTalking); -typedef void (*HUD_DIRECTORMESSAGE_FUNC)( int iSize, void *pbuf ); -typedef int ( *HUD_STUDIO_INTERFACE_FUNC )( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); -typedef void (*HUD_CHATINPUTPOSITION_FUNC)( int *x, int *y ); -typedef int (*HUD_GETPLAYERTEAM)(int iplayer); -typedef void *(*CLIENTFACTORY)(); // this should be CreateInterfaceFn but that means including interface.h - // which is a C++ file and some of the client files a C only... - // so we return a void * which we then do a typecast on later. - - -// Pointers to the exported client functions themselves -typedef struct -{ - INITIALIZE_FUNC pInitFunc; - HUD_INIT_FUNC pHudInitFunc; - HUD_VIDINIT_FUNC pHudVidInitFunc; - HUD_REDRAW_FUNC pHudRedrawFunc; - HUD_UPDATECLIENTDATA_FUNC pHudUpdateClientDataFunc; - HUD_RESET_FUNC pHudResetFunc; - HUD_CLIENTMOVE_FUNC pClientMove; - HUD_CLIENTMOVEINIT_FUNC pClientMoveInit; - HUD_TEXTURETYPE_FUNC pClientTextureType; - HUD_IN_ACTIVATEMOUSE_FUNC pIN_ActivateMouse; - HUD_IN_DEACTIVATEMOUSE_FUNC pIN_DeactivateMouse; - HUD_IN_MOUSEEVENT_FUNC pIN_MouseEvent; - HUD_IN_CLEARSTATES_FUNC pIN_ClearStates; - HUD_IN_ACCUMULATE_FUNC pIN_Accumulate; - HUD_CL_CREATEMOVE_FUNC pCL_CreateMove; - HUD_CL_ISTHIRDPERSON_FUNC pCL_IsThirdPerson; - HUD_CL_GETCAMERAOFFSETS_FUNC pCL_GetCameraOffsets; - HUD_KB_FIND_FUNC pFindKey; - HUD_CAMTHINK_FUNC pCamThink; - HUD_CALCREF_FUNC pCalcRefdef; - HUD_ADDENTITY_FUNC pAddEntity; - HUD_CREATEENTITIES_FUNC pCreateEntities; - HUD_DRAWNORMALTRIS_FUNC pDrawNormalTriangles; - HUD_DRAWTRANSTRIS_FUNC pDrawTransparentTriangles; - HUD_STUDIOEVENT_FUNC pStudioEvent; - HUD_POSTRUNCMD_FUNC pPostRunCmd; - HUD_SHUTDOWN_FUNC pShutdown; - HUD_TXFERLOCALOVERRIDES_FUNC pTxferLocalOverrides; - HUD_PROCESSPLAYERSTATE_FUNC pProcessPlayerState; - HUD_TXFERPREDICTIONDATA_FUNC pTxferPredictionData; - HUD_DEMOREAD_FUNC pReadDemoBuffer; - HUD_CONNECTIONLESS_FUNC pConnectionlessPacket; - HUD_GETHULLBOUNDS_FUNC pGetHullBounds; - HUD_FRAME_FUNC pHudFrame; - HUD_KEY_EVENT_FUNC pKeyEvent; - HUD_TEMPENTUPDATE_FUNC pTempEntUpdate; - HUD_GETUSERENTITY_FUNC pGetUserEntity; - HUD_VOICESTATUS_FUNC pVoiceStatus; // Possibly null on old client dlls. - HUD_DIRECTORMESSAGE_FUNC pDirectorMessage; // Possibly null on old client dlls. - HUD_STUDIO_INTERFACE_FUNC pStudioInterface; // Not used by all clients - HUD_CHATINPUTPOSITION_FUNC pChatInputPosition; // Not used by all clients - HUD_GETPLAYERTEAM pGetPlayerTeam; // Not used by all clients - CLIENTFACTORY pClientFactory; -} cldll_func_t; - -// Function type declarations for client destination functions -typedef void (*DST_INITIALIZE_FUNC) ( struct cl_enginefuncs_s**, int *); -typedef void (*DST_HUD_INIT_FUNC) ( void ); -typedef void (*DST_HUD_VIDINIT_FUNC) ( void ); -typedef void (*DST_HUD_REDRAW_FUNC) ( float*, int* ); -typedef void (*DST_HUD_UPDATECLIENTDATA_FUNC) ( struct client_data_s**, float* ); -typedef void (*DST_HUD_RESET_FUNC) ( void ); -typedef void (*DST_HUD_CLIENTMOVE_FUNC)( struct playermove_s **, qboolean * ); -typedef void (*DST_HUD_CLIENTMOVEINIT_FUNC)( struct playermove_s ** ); -typedef void (*DST_HUD_TEXTURETYPE_FUNC)( char ** ); -typedef void (*DST_HUD_IN_ACTIVATEMOUSE_FUNC) ( void ); -typedef void (*DST_HUD_IN_DEACTIVATEMOUSE_FUNC) ( void ); -typedef void (*DST_HUD_IN_MOUSEEVENT_FUNC) ( int * ); -typedef void (*DST_HUD_IN_CLEARSTATES_FUNC) ( void ); -typedef void (*DST_HUD_IN_ACCUMULATE_FUNC ) ( void ); -typedef void (*DST_HUD_CL_CREATEMOVE_FUNC) ( float *, struct usercmd_s **, int * ); -typedef void (*DST_HUD_CL_ISTHIRDPERSON_FUNC) ( void ); -typedef void (*DST_HUD_CL_GETCAMERAOFFSETS_FUNC )( float ** ); -typedef void (*DST_HUD_KB_FIND_FUNC) ( const char ** ); -typedef void (*DST_HUD_CAMTHINK_FUNC )( void ); -typedef void (*DST_HUD_CALCREF_FUNC ) ( struct ref_params_s ** ); -typedef void (*DST_HUD_ADDENTITY_FUNC ) ( int *, struct cl_entity_s **, const char ** ); -typedef void (*DST_HUD_CREATEENTITIES_FUNC ) ( void ); -typedef void (*DST_HUD_DRAWNORMALTRIS_FUNC ) ( void ); -typedef void (*DST_HUD_DRAWTRANSTRIS_FUNC ) ( void ); -typedef void (*DST_HUD_STUDIOEVENT_FUNC ) ( const struct mstudioevent_s **, const struct cl_entity_s ** ); -typedef void (*DST_HUD_POSTRUNCMD_FUNC ) ( struct local_state_s **, struct local_state_s **, struct usercmd_s **, int *, double *, unsigned int * ); -typedef void (*DST_HUD_SHUTDOWN_FUNC ) ( void ); -typedef void (*DST_HUD_TXFERLOCALOVERRIDES_FUNC )( struct entity_state_s **, const struct clientdata_s ** ); -typedef void (*DST_HUD_PROCESSPLAYERSTATE_FUNC )( struct entity_state_s **, const struct entity_state_s ** ); -typedef void (*DST_HUD_TXFERPREDICTIONDATA_FUNC ) ( struct entity_state_s **, const struct entity_state_s **, struct clientdata_s **, const struct clientdata_s **, struct weapon_data_s **, const struct weapon_data_s ** ); -typedef void (*DST_HUD_DEMOREAD_FUNC ) ( int *, unsigned char ** ); -typedef void (*DST_HUD_CONNECTIONLESS_FUNC )( const struct netadr_s **, const char **, char **, int ** ); -typedef void (*DST_HUD_GETHULLBOUNDS_FUNC ) ( int *, float **, float ** ); -typedef void (*DST_HUD_FRAME_FUNC) ( double * ); -typedef void (*DST_HUD_KEY_EVENT_FUNC ) ( int *, int *, const char ** ); -typedef void (*DST_HUD_TEMPENTUPDATE_FUNC) ( double *, double *, double *, struct tempent_s ***, struct tempent_s ***, int ( **Callback_AddVisibleEntity )( struct cl_entity_s *pEntity ), void ( **Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ) ); -typedef void (*DST_HUD_GETUSERENTITY_FUNC ) ( int * ); -typedef void (*DST_HUD_VOICESTATUS_FUNC)(int *, qboolean *); -typedef void (*DST_HUD_DIRECTORMESSAGE_FUNC)( int *, void ** ); -typedef void (*DST_HUD_STUDIO_INTERFACE_FUNC ) ( int *, struct r_studio_interface_s ***, struct engine_studio_api_s ** ); -typedef void (*DST_HUD_CHATINPUTPOSITION_FUNC)( int **, int ** ); -typedef void (*DST_HUD_GETPLAYERTEAM)(int); - -// Pointers to the client destination functions -typedef struct -{ - DST_INITIALIZE_FUNC pInitFunc; - DST_HUD_INIT_FUNC pHudInitFunc; - DST_HUD_VIDINIT_FUNC pHudVidInitFunc; - DST_HUD_REDRAW_FUNC pHudRedrawFunc; - DST_HUD_UPDATECLIENTDATA_FUNC pHudUpdateClientDataFunc; - DST_HUD_RESET_FUNC pHudResetFunc; - DST_HUD_CLIENTMOVE_FUNC pClientMove; - DST_HUD_CLIENTMOVEINIT_FUNC pClientMoveInit; - DST_HUD_TEXTURETYPE_FUNC pClientTextureType; - DST_HUD_IN_ACTIVATEMOUSE_FUNC pIN_ActivateMouse; - DST_HUD_IN_DEACTIVATEMOUSE_FUNC pIN_DeactivateMouse; - DST_HUD_IN_MOUSEEVENT_FUNC pIN_MouseEvent; - DST_HUD_IN_CLEARSTATES_FUNC pIN_ClearStates; - DST_HUD_IN_ACCUMULATE_FUNC pIN_Accumulate; - DST_HUD_CL_CREATEMOVE_FUNC pCL_CreateMove; - DST_HUD_CL_ISTHIRDPERSON_FUNC pCL_IsThirdPerson; - DST_HUD_CL_GETCAMERAOFFSETS_FUNC pCL_GetCameraOffsets; - DST_HUD_KB_FIND_FUNC pFindKey; - DST_HUD_CAMTHINK_FUNC pCamThink; - DST_HUD_CALCREF_FUNC pCalcRefdef; - DST_HUD_ADDENTITY_FUNC pAddEntity; - DST_HUD_CREATEENTITIES_FUNC pCreateEntities; - DST_HUD_DRAWNORMALTRIS_FUNC pDrawNormalTriangles; - DST_HUD_DRAWTRANSTRIS_FUNC pDrawTransparentTriangles; - DST_HUD_STUDIOEVENT_FUNC pStudioEvent; - DST_HUD_POSTRUNCMD_FUNC pPostRunCmd; - DST_HUD_SHUTDOWN_FUNC pShutdown; - DST_HUD_TXFERLOCALOVERRIDES_FUNC pTxferLocalOverrides; - DST_HUD_PROCESSPLAYERSTATE_FUNC pProcessPlayerState; - DST_HUD_TXFERPREDICTIONDATA_FUNC pTxferPredictionData; - DST_HUD_DEMOREAD_FUNC pReadDemoBuffer; - DST_HUD_CONNECTIONLESS_FUNC pConnectionlessPacket; - DST_HUD_GETHULLBOUNDS_FUNC pGetHullBounds; - DST_HUD_FRAME_FUNC pHudFrame; - DST_HUD_KEY_EVENT_FUNC pKeyEvent; - DST_HUD_TEMPENTUPDATE_FUNC pTempEntUpdate; - DST_HUD_GETUSERENTITY_FUNC pGetUserEntity; - DST_HUD_VOICESTATUS_FUNC pVoiceStatus; // Possibly null on old client dlls. - DST_HUD_DIRECTORMESSAGE_FUNC pDirectorMessage; // Possibly null on old client dlls. - DST_HUD_STUDIO_INTERFACE_FUNC pStudioInterface; // Not used by all clients - DST_HUD_CHATINPUTPOSITION_FUNC pChatInputPosition; // Not used by all clients - DST_HUD_GETPLAYERTEAM pGetPlayerTeam; // Not used by all clients -} cldll_func_dst_t; - - - - -// ******************************************************** -// Functions exported by the engine -// ******************************************************** - -// Function type declarations for engine exports -typedef HLSPRITE (*pfnEngSrc_pfnSPR_Load_t ) ( const char *szPicName ); -typedef int (*pfnEngSrc_pfnSPR_Frames_t ) ( HLSPRITE hPic ); -typedef int (*pfnEngSrc_pfnSPR_Height_t ) ( HLSPRITE hPic, int frame ); -typedef int (*pfnEngSrc_pfnSPR_Width_t ) ( HLSPRITE hPic, int frame ); -typedef void (*pfnEngSrc_pfnSPR_Set_t ) ( HLSPRITE hPic, int r, int g, int b ); -typedef void (*pfnEngSrc_pfnSPR_Draw_t ) ( int frame, int x, int y, const struct rect_s *prc ); -typedef void (*pfnEngSrc_pfnSPR_DrawHoles_t ) ( int frame, int x, int y, const struct rect_s *prc ); -typedef void (*pfnEngSrc_pfnSPR_DrawAdditive_t ) ( int frame, int x, int y, const struct rect_s *prc ); -typedef void (*pfnEngSrc_pfnSPR_EnableScissor_t ) ( int x, int y, int width, int height ); -typedef void (*pfnEngSrc_pfnSPR_DisableScissor_t ) ( void ); -typedef struct client_sprite_s * (*pfnEngSrc_pfnSPR_GetList_t ) ( const char *psz, int *piCount ); -typedef void (*pfnEngSrc_pfnFillRGBA_t ) ( int x, int y, int width, int height, int r, int g, int b, int a ); -typedef int (*pfnEngSrc_pfnGetScreenInfo_t ) ( struct SCREENINFO_s *pscrinfo ); -typedef void (*pfnEngSrc_pfnSetCrosshair_t ) ( HLSPRITE hspr, wrect_t rc, int r, int g, int b ); -typedef struct cvar_s * (*pfnEngSrc_pfnRegisterVariable_t ) ( const char *szName, const char *szValue, int flags ); -typedef float (*pfnEngSrc_pfnGetCvarFloat_t ) ( const char *szName ); -typedef char* (*pfnEngSrc_pfnGetCvarString_t ) ( const char *szName ); -typedef int (*pfnEngSrc_pfnAddCommand_t ) ( const char *cmd_name, void (*pfnEngSrc_function)(void) ); -typedef int (*pfnEngSrc_pfnHookUserMsg_t ) ( const char *szMsgName, pfnUserMsgHook pfn ); -typedef int (*pfnEngSrc_pfnServerCmd_t ) ( const char *szCmdString ); -typedef int (*pfnEngSrc_pfnClientCmd_t ) ( const char *szCmdString ); -typedef void (*pfnEngSrc_pfnPrimeMusicStream_t ) ( const char *szFilename, int looping ); -typedef void (*pfnEngSrc_pfnGetPlayerInfo_t ) ( int ent_num, struct hud_player_info_s *pinfo ); -typedef void (*pfnEngSrc_pfnPlaySoundByName_t ) ( const char *szSound, float volume ); -typedef void (*pfnEngSrc_pfnPlaySoundByNameAtPitch_t ) ( const char *szSound, float volume, int pitch ); -typedef void (*pfnEngSrc_pfnPlaySoundVoiceByName_t ) ( const char *szSound, float volume, int pitch ); -typedef void (*pfnEngSrc_pfnPlaySoundByIndex_t ) ( int iSound, float volume ); -typedef void (*pfnEngSrc_pfnAngleVectors_t ) ( const float * vecAngles, float * forward, float * right, float * up ); -typedef struct client_textmessage_s*(*pfnEngSrc_pfnTextMessageGet_t ) ( const char *pName ); -typedef int (*pfnEngSrc_pfnDrawCharacter_t ) ( int x, int y, int number, int r, int g, int b ); -typedef int (*pfnEngSrc_pfnDrawConsoleString_t ) ( int x, int y, const char *string ); -typedef void (*pfnEngSrc_pfnDrawSetTextColor_t ) ( float r, float g, float b ); -typedef void (*pfnEngSrc_pfnDrawConsoleStringLen_t )( const char *string, int *length, int *height ); -typedef void (*pfnEngSrc_pfnConsolePrint_t ) ( const char *string ); -typedef void (*pfnEngSrc_pfnCenterPrint_t ) ( const char *string ); -typedef int (*pfnEngSrc_GetWindowCenterX_t ) ( void ); -typedef int (*pfnEngSrc_GetWindowCenterY_t ) ( void ); -typedef void (*pfnEngSrc_GetViewAngles_t ) ( float * ); -typedef void (*pfnEngSrc_SetViewAngles_t ) ( float * ); -typedef int (*pfnEngSrc_GetMaxClients_t ) ( void ); -typedef void (*pfnEngSrc_Cvar_SetValue_t ) ( const char *cvar, float value ); -typedef int (*pfnEngSrc_Cmd_Argc_t) (void); -typedef char * (*pfnEngSrc_Cmd_Argv_t ) ( int arg ); -typedef void (*pfnEngSrc_Con_Printf_t ) ( const char *fmt, ... ); -typedef void (*pfnEngSrc_Con_DPrintf_t ) ( const char *fmt, ... ); -typedef void (*pfnEngSrc_Con_NPrintf_t ) ( int pos, const char *fmt, ... ); -typedef void (*pfnEngSrc_Con_NXPrintf_t ) ( struct con_nprint_s *info, const char *fmt, ... ); -typedef const char * (*pfnEngSrc_PhysInfo_ValueForKey_t ) ( const char *key ); -typedef const char * (*pfnEngSrc_ServerInfo_ValueForKey_t )( const char *key ); -typedef float (*pfnEngSrc_GetClientMaxspeed_t ) ( void ); -typedef int (*pfnEngSrc_CheckParm_t ) ( const char *parm, char **ppnext ); -typedef void (*pfnEngSrc_Key_Event_t ) ( int key, int down ); -typedef void (*pfnEngSrc_GetMousePosition_t ) ( int *mx, int *my ); -typedef int (*pfnEngSrc_IsNoClipping_t ) ( void ); -typedef struct cl_entity_s * (*pfnEngSrc_GetLocalPlayer_t ) ( void ); -typedef struct cl_entity_s * (*pfnEngSrc_GetViewModel_t ) ( void ); -typedef struct cl_entity_s * (*pfnEngSrc_GetEntityByIndex_t ) ( int idx ); -typedef float (*pfnEngSrc_GetClientTime_t ) ( void ); -typedef void (*pfnEngSrc_V_CalcShake_t ) ( void ); -typedef void (*pfnEngSrc_V_ApplyShake_t ) ( float *origin, float *angles, float factor ); -typedef int (*pfnEngSrc_PM_PointContents_t ) ( float *point, int *truecontents ); -typedef int (*pfnEngSrc_PM_WaterEntity_t ) ( float *p ); -typedef struct pmtrace_s * (*pfnEngSrc_PM_TraceLine_t ) ( float *start, float *end, int flags, int usehull, int ignore_pe ); -typedef struct model_s * (*pfnEngSrc_CL_LoadModel_t ) ( const char *modelname, int *index ); -typedef int (*pfnEngSrc_CL_CreateVisibleEntity_t ) ( int type, struct cl_entity_s *ent ); -typedef const struct model_s * (*pfnEngSrc_GetSpritePointer_t ) ( HLSPRITE hSprite ); -typedef void (*pfnEngSrc_pfnPlaySoundByNameAtLocation_t ) ( const char *szSound, float volume, float *origin ); -typedef unsigned short (*pfnEngSrc_pfnPrecacheEvent_t ) ( int type, const char* psz ); -typedef void (*pfnEngSrc_pfnPlaybackEvent_t ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); -typedef void (*pfnEngSrc_pfnWeaponAnim_t ) ( int iAnim, int body ); -typedef float (*pfnEngSrc_pfnRandomFloat_t ) ( float flLow, float flHigh ); -typedef int32 (*pfnEngSrc_pfnRandomLong_t ) ( int32 lLow, int32 lHigh ); -typedef void (*pfnEngSrc_pfnHookEvent_t ) ( const char *name, void ( *pfnEvent )( struct event_args_s *args ) ); -typedef int (*pfnEngSrc_Con_IsVisible_t) (); -typedef const char * (*pfnEngSrc_pfnGetGameDirectory_t ) ( void ); -typedef struct cvar_s * (*pfnEngSrc_pfnGetCvarPointer_t ) ( const char *szName ); -typedef const char * (*pfnEngSrc_Key_LookupBinding_t ) ( const char *pBinding ); -typedef const char * (*pfnEngSrc_pfnGetLevelName_t ) ( void ); -typedef void (*pfnEngSrc_pfnGetScreenFade_t ) ( struct screenfade_s *fade ); -typedef void (*pfnEngSrc_pfnSetScreenFade_t ) ( struct screenfade_s *fade ); -typedef void * (*pfnEngSrc_VGui_GetPanel_t ) ( ); -typedef void (*pfnEngSrc_VGui_ViewportPaintBackground_t ) (int extents[4]); -typedef byte* (*pfnEngSrc_COM_LoadFile_t ) ( const char *path, int usehunk, int *pLength ); -typedef char* (*pfnEngSrc_COM_ParseFile_t ) ( char *data, char *token ); -typedef void (*pfnEngSrc_COM_FreeFile_t) ( void *buffer ); -typedef struct triangleapi_s * pTriAPI; -typedef struct efx_api_s * pEfxAPI; -typedef struct event_api_s * pEventAPI; -typedef struct demo_api_s * pDemoAPI; -typedef struct net_api_s * pNetAPI; -typedef struct IVoiceTweak_s * pVoiceTweak; -typedef int (*pfnEngSrc_IsSpectateOnly_t ) ( void ); -typedef struct model_s * (*pfnEngSrc_LoadMapSprite_t ) ( const char *filename ); -typedef void (*pfnEngSrc_COM_AddAppDirectoryToSearchPath_t ) ( const char *pszBaseDir, const char *appName ); -typedef int (*pfnEngSrc_COM_ExpandFilename_t) ( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); -typedef const char * (*pfnEngSrc_PlayerInfo_ValueForKey_t )( int playerNum, const char *key ); -typedef void (*pfnEngSrc_PlayerInfo_SetValueForKey_t )( const char *key, const char *value ); -typedef qboolean (*pfnEngSrc_GetPlayerUniqueID_t)(int iPlayer, char playerID[16]); -typedef int (*pfnEngSrc_GetTrackerIDForPlayer_t)(int playerSlot); -typedef int (*pfnEngSrc_GetPlayerForTrackerID_t)(int trackerID); -typedef int (*pfnEngSrc_pfnServerCmdUnreliable_t )( char *szCmdString ); -typedef void (*pfnEngSrc_GetMousePos_t )(struct tagPOINT *ppt); -typedef void (*pfnEngSrc_SetMousePos_t )(int x, int y); -typedef void (*pfnEngSrc_SetMouseEnable_t)(qboolean fEnable); -typedef struct cvar_s * (*pfnEngSrc_GetFirstCVarPtr_t)(); -typedef unsigned int (*pfnEngSrc_GetFirstCmdFunctionHandle_t)(); -typedef unsigned int (*pfnEngSrc_GetNextCmdFunctionHandle_t)(unsigned int cmdhandle); -typedef const char * (*pfnEngSrc_GetCmdFunctionName_t)(unsigned int cmdhandle); -typedef float (*pfnEngSrc_GetClientOldTime_t)(); -typedef float (*pfnEngSrc_GetServerGravityValue_t)(); -typedef struct model_s * (*pfnEngSrc_GetModelByIndex_t)( int index ); -typedef void (*pfnEngSrc_pfnSetFilterMode_t )( int mode ); -typedef void (*pfnEngSrc_pfnSetFilterColor_t )( float r, float g, float b ); -typedef void (*pfnEngSrc_pfnSetFilterBrightness_t )( float brightness ); -typedef sequenceEntry_s* (*pfnEngSrc_pfnSequenceGet_t )( const char *fileName, const char* entryName ); -typedef void (*pfnEngSrc_pfnSPR_DrawGeneric_t )( int frame, int x, int y, const struct rect_s *prc, int src, int dest, int w, int h ); -typedef sentenceEntry_s* (*pfnEngSrc_pfnSequencePickSentence_t )( const char *sentenceName, int pickMethod, int* entryPicked ); -// draw a complete string -typedef int (*pfnEngSrc_pfnDrawString_t ) ( int x, int y, const char *str, int r, int g, int b ); -typedef int (*pfnEngSrc_pfnDrawStringReverse_t ) ( int x, int y, const char *str, int r, int g, int b ); -typedef const char * (*pfnEngSrc_LocalPlayerInfo_ValueForKey_t )( const char *key ); -typedef int (*pfnEngSrc_pfnVGUI2DrawCharacter_t ) ( int x, int y, int ch, unsigned int font ); -typedef int (*pfnEngSrc_pfnVGUI2DrawCharacterAdd_t ) ( int x, int y, int ch, int r, int g, int b, unsigned int font); -typedef unsigned int (*pfnEngSrc_COM_GetApproxWavePlayLength ) ( const char * filename); -typedef void * (*pfnEngSrc_pfnGetCareerUI_t)(); -typedef void (*pfnEngSrc_Cvar_Set_t ) ( char *cvar, char *value ); -typedef int (*pfnEngSrc_pfnIsPlayingCareerMatch_t)(); -typedef double (*pfnEngSrc_GetAbsoluteTime_t) ( void ); -typedef void (*pfnEngSrc_pfnProcessTutorMessageDecayBuffer_t)(int *buffer, int bufferLength); -typedef void (*pfnEngSrc_pfnConstructTutorMessageDecayBuffer_t)(int *buffer, int bufferLength); -typedef void (*pfnEngSrc_pfnResetTutorMessageDecayData_t)(); -typedef void (*pfnEngSrc_pfnFillRGBABlend_t ) ( int x, int y, int width, int height, int r, int g, int b, int a ); -typedef int (*pfnEngSrc_pfnGetAppID_t) ( void ); -typedef cmdalias_t* (*pfnEngSrc_pfnGetAliases_t) ( void ); -typedef void (*pfnEngSrc_pfnVguiWrap2_GetMouseDelta_t) ( int *x, int *y ); - -// Pointers to the exported engine functions themselves -typedef struct cl_enginefuncs_s -{ - pfnEngSrc_pfnSPR_Load_t pfnSPR_Load; - pfnEngSrc_pfnSPR_Frames_t pfnSPR_Frames; - pfnEngSrc_pfnSPR_Height_t pfnSPR_Height; - pfnEngSrc_pfnSPR_Width_t pfnSPR_Width; - pfnEngSrc_pfnSPR_Set_t pfnSPR_Set; - pfnEngSrc_pfnSPR_Draw_t pfnSPR_Draw; - pfnEngSrc_pfnSPR_DrawHoles_t pfnSPR_DrawHoles; - pfnEngSrc_pfnSPR_DrawAdditive_t pfnSPR_DrawAdditive; - pfnEngSrc_pfnSPR_EnableScissor_t pfnSPR_EnableScissor; - pfnEngSrc_pfnSPR_DisableScissor_t pfnSPR_DisableScissor; - pfnEngSrc_pfnSPR_GetList_t pfnSPR_GetList; - pfnEngSrc_pfnFillRGBA_t pfnFillRGBA; - pfnEngSrc_pfnGetScreenInfo_t pfnGetScreenInfo; - pfnEngSrc_pfnSetCrosshair_t pfnSetCrosshair; - pfnEngSrc_pfnRegisterVariable_t pfnRegisterVariable; - pfnEngSrc_pfnGetCvarFloat_t pfnGetCvarFloat; - pfnEngSrc_pfnGetCvarString_t pfnGetCvarString; - pfnEngSrc_pfnAddCommand_t pfnAddCommand; - pfnEngSrc_pfnHookUserMsg_t pfnHookUserMsg; - pfnEngSrc_pfnServerCmd_t pfnServerCmd; - pfnEngSrc_pfnClientCmd_t pfnClientCmd; - pfnEngSrc_pfnGetPlayerInfo_t pfnGetPlayerInfo; - pfnEngSrc_pfnPlaySoundByName_t pfnPlaySoundByName; - pfnEngSrc_pfnPlaySoundByIndex_t pfnPlaySoundByIndex; - pfnEngSrc_pfnAngleVectors_t pfnAngleVectors; - pfnEngSrc_pfnTextMessageGet_t pfnTextMessageGet; - pfnEngSrc_pfnDrawCharacter_t pfnDrawCharacter; - pfnEngSrc_pfnDrawConsoleString_t pfnDrawConsoleString; - pfnEngSrc_pfnDrawSetTextColor_t pfnDrawSetTextColor; - pfnEngSrc_pfnDrawConsoleStringLen_t pfnDrawConsoleStringLen; - pfnEngSrc_pfnConsolePrint_t pfnConsolePrint; - pfnEngSrc_pfnCenterPrint_t pfnCenterPrint; - pfnEngSrc_GetWindowCenterX_t GetWindowCenterX; - pfnEngSrc_GetWindowCenterY_t GetWindowCenterY; - pfnEngSrc_GetViewAngles_t GetViewAngles; - pfnEngSrc_SetViewAngles_t SetViewAngles; - pfnEngSrc_GetMaxClients_t GetMaxClients; - pfnEngSrc_Cvar_SetValue_t Cvar_SetValue; - pfnEngSrc_Cmd_Argc_t Cmd_Argc; - pfnEngSrc_Cmd_Argv_t Cmd_Argv; - pfnEngSrc_Con_Printf_t Con_Printf; - pfnEngSrc_Con_DPrintf_t Con_DPrintf; - pfnEngSrc_Con_NPrintf_t Con_NPrintf; - pfnEngSrc_Con_NXPrintf_t Con_NXPrintf; - pfnEngSrc_PhysInfo_ValueForKey_t PhysInfo_ValueForKey; - pfnEngSrc_ServerInfo_ValueForKey_t ServerInfo_ValueForKey; - pfnEngSrc_GetClientMaxspeed_t GetClientMaxspeed; - pfnEngSrc_CheckParm_t CheckParm; - pfnEngSrc_Key_Event_t Key_Event; - pfnEngSrc_GetMousePosition_t GetMousePosition; - pfnEngSrc_IsNoClipping_t IsNoClipping; - pfnEngSrc_GetLocalPlayer_t GetLocalPlayer; - pfnEngSrc_GetViewModel_t GetViewModel; - pfnEngSrc_GetEntityByIndex_t GetEntityByIndex; - pfnEngSrc_GetClientTime_t GetClientTime; - pfnEngSrc_V_CalcShake_t V_CalcShake; - pfnEngSrc_V_ApplyShake_t V_ApplyShake; - pfnEngSrc_PM_PointContents_t PM_PointContents; - pfnEngSrc_PM_WaterEntity_t PM_WaterEntity; - pfnEngSrc_PM_TraceLine_t PM_TraceLine; - pfnEngSrc_CL_LoadModel_t CL_LoadModel; - pfnEngSrc_CL_CreateVisibleEntity_t CL_CreateVisibleEntity; - pfnEngSrc_GetSpritePointer_t GetSpritePointer; - pfnEngSrc_pfnPlaySoundByNameAtLocation_t pfnPlaySoundByNameAtLocation; - pfnEngSrc_pfnPrecacheEvent_t pfnPrecacheEvent; - pfnEngSrc_pfnPlaybackEvent_t pfnPlaybackEvent; - pfnEngSrc_pfnWeaponAnim_t pfnWeaponAnim; - pfnEngSrc_pfnRandomFloat_t pfnRandomFloat; - pfnEngSrc_pfnRandomLong_t pfnRandomLong; - pfnEngSrc_pfnHookEvent_t pfnHookEvent; - pfnEngSrc_Con_IsVisible_t Con_IsVisible; - pfnEngSrc_pfnGetGameDirectory_t pfnGetGameDirectory; - pfnEngSrc_pfnGetCvarPointer_t pfnGetCvarPointer; - pfnEngSrc_Key_LookupBinding_t Key_LookupBinding; - pfnEngSrc_pfnGetLevelName_t pfnGetLevelName; - pfnEngSrc_pfnGetScreenFade_t pfnGetScreenFade; - pfnEngSrc_pfnSetScreenFade_t pfnSetScreenFade; - pfnEngSrc_VGui_GetPanel_t VGui_GetPanel; - pfnEngSrc_VGui_ViewportPaintBackground_t VGui_ViewportPaintBackground; - pfnEngSrc_COM_LoadFile_t COM_LoadFile; - pfnEngSrc_COM_ParseFile_t COM_ParseFile; - pfnEngSrc_COM_FreeFile_t COM_FreeFile; - struct triangleapi_s *pTriAPI; - struct efx_api_s *pEfxAPI; - struct event_api_s *pEventAPI; - struct demo_api_s *pDemoAPI; - struct net_api_s *pNetAPI; - struct IVoiceTweak_s *pVoiceTweak; - pfnEngSrc_IsSpectateOnly_t IsSpectateOnly; - pfnEngSrc_LoadMapSprite_t LoadMapSprite; - pfnEngSrc_COM_AddAppDirectoryToSearchPath_t COM_AddAppDirectoryToSearchPath; - pfnEngSrc_COM_ExpandFilename_t COM_ExpandFilename; - pfnEngSrc_PlayerInfo_ValueForKey_t PlayerInfo_ValueForKey; - pfnEngSrc_PlayerInfo_SetValueForKey_t PlayerInfo_SetValueForKey; - pfnEngSrc_GetPlayerUniqueID_t GetPlayerUniqueID; - pfnEngSrc_GetTrackerIDForPlayer_t GetTrackerIDForPlayer; - pfnEngSrc_GetPlayerForTrackerID_t GetPlayerForTrackerID; - pfnEngSrc_pfnServerCmdUnreliable_t pfnServerCmdUnreliable; - pfnEngSrc_GetMousePos_t pfnGetMousePos; - pfnEngSrc_SetMousePos_t pfnSetMousePos; - pfnEngSrc_SetMouseEnable_t pfnSetMouseEnable; - pfnEngSrc_GetFirstCVarPtr_t GetFirstCvarPtr; - pfnEngSrc_GetFirstCmdFunctionHandle_t GetFirstCmdFunctionHandle; - pfnEngSrc_GetNextCmdFunctionHandle_t GetNextCmdFunctionHandle; - pfnEngSrc_GetCmdFunctionName_t GetCmdFunctionName; - pfnEngSrc_GetClientOldTime_t hudGetClientOldTime; - pfnEngSrc_GetServerGravityValue_t hudGetServerGravityValue; - pfnEngSrc_GetModelByIndex_t hudGetModelByIndex; - pfnEngSrc_pfnSetFilterMode_t pfnSetFilterMode; - pfnEngSrc_pfnSetFilterColor_t pfnSetFilterColor; - pfnEngSrc_pfnSetFilterBrightness_t pfnSetFilterBrightness; - pfnEngSrc_pfnSequenceGet_t pfnSequenceGet; - pfnEngSrc_pfnSPR_DrawGeneric_t pfnSPR_DrawGeneric; - pfnEngSrc_pfnSequencePickSentence_t pfnSequencePickSentence; - pfnEngSrc_pfnDrawString_t pfnDrawString; - pfnEngSrc_pfnDrawStringReverse_t pfnDrawStringReverse; - pfnEngSrc_LocalPlayerInfo_ValueForKey_t LocalPlayerInfo_ValueForKey; - pfnEngSrc_pfnVGUI2DrawCharacter_t pfnVGUI2DrawCharacter; - pfnEngSrc_pfnVGUI2DrawCharacterAdd_t pfnVGUI2DrawCharacterAdd; - pfnEngSrc_COM_GetApproxWavePlayLength COM_GetApproxWavePlayLength; - pfnEngSrc_pfnGetCareerUI_t pfnGetCareerUI; - pfnEngSrc_Cvar_Set_t Cvar_Set; - pfnEngSrc_pfnIsPlayingCareerMatch_t pfnIsCareerMatch; - pfnEngSrc_pfnPlaySoundVoiceByName_t pfnPlaySoundVoiceByName; - pfnEngSrc_pfnPrimeMusicStream_t pfnPrimeMusicStream; - pfnEngSrc_GetAbsoluteTime_t GetAbsoluteTime; - pfnEngSrc_pfnProcessTutorMessageDecayBuffer_t pfnProcessTutorMessageDecayBuffer; - pfnEngSrc_pfnConstructTutorMessageDecayBuffer_t pfnConstructTutorMessageDecayBuffer; - pfnEngSrc_pfnResetTutorMessageDecayData_t pfnResetTutorMessageDecayData; - pfnEngSrc_pfnPlaySoundByNameAtPitch_t pfnPlaySoundByNameAtPitch; - pfnEngSrc_pfnFillRGBABlend_t pfnFillRGBABlend; - pfnEngSrc_pfnGetAppID_t pfnGetAppID; - pfnEngSrc_pfnGetAliases_t pfnGetAliasList; - pfnEngSrc_pfnVguiWrap2_GetMouseDelta_t pfnVguiWrap2_GetMouseDelta; -} cl_enginefunc_t; - -// Function type declarations for engine destination functions -typedef void (*pfnEngDst_pfnSPR_Load_t ) ( const char ** ); -typedef void (*pfnEngDst_pfnSPR_Frames_t ) ( HLSPRITE * ); -typedef void (*pfnEngDst_pfnSPR_Height_t ) ( HLSPRITE *, int * ); -typedef void (*pfnEngDst_pfnSPR_Width_t ) ( HLSPRITE *, int * ); -typedef void (*pfnEngDst_pfnSPR_Set_t ) ( HLSPRITE *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnSPR_Draw_t ) ( int *, int *, int *, const struct rect_s ** ); -typedef void (*pfnEngDst_pfnSPR_DrawHoles_t ) ( int *, int *, int *, const struct rect_s ** ); -typedef void (*pfnEngDst_pfnSPR_DrawAdditive_t ) ( int *, int *, int *, const struct rect_s ** ); -typedef void (*pfnEngDst_pfnSPR_EnableScissor_t ) ( int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnSPR_DisableScissor_t ) ( void ); -typedef void (*pfnEngDst_pfnSPR_GetList_t ) ( char **, int ** ); -typedef void (*pfnEngDst_pfnFillRGBA_t ) ( int *, int *, int *, int *, int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnGetScreenInfo_t ) ( struct SCREENINFO_s ** ); -typedef void (*pfnEngDst_pfnSetCrosshair_t ) ( HLSPRITE *, struct rect_s *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnRegisterVariable_t ) ( char **, char **, int * ); -typedef void (*pfnEngDst_pfnGetCvarFloat_t ) ( char ** ); -typedef void (*pfnEngDst_pfnGetCvarString_t ) ( char ** ); -typedef void (*pfnEngDst_pfnAddCommand_t ) ( char **, void (**pfnEngDst_function)(void) ); -typedef void (*pfnEngDst_pfnHookUserMsg_t ) ( char **, pfnUserMsgHook * ); -typedef void (*pfnEngDst_pfnServerCmd_t ) ( char ** ); -typedef void (*pfnEngDst_pfnClientCmd_t ) ( char ** ); -typedef void (*pfnEngDst_pfnPrimeMusicStream_t ) ( char **, int *); -typedef void (*pfnEngDst_pfnGetPlayerInfo_t ) ( int *, struct hud_player_info_s ** ); -typedef void (*pfnEngDst_pfnPlaySoundByName_t ) ( char **, float * ); -typedef void (*pfnEngDst_pfnPlaySoundByNameAtPitch_t ) ( char **, float *, int * ); -typedef void (*pfnEngDst_pfnPlaySoundVoiceByName_t ) (char **, float * ); -typedef void (*pfnEngDst_pfnPlaySoundByIndex_t ) ( int *, float * ); -typedef void (*pfnEngDst_pfnAngleVectors_t ) ( const float * *, float * *, float * *, float * * ); -typedef void (*pfnEngDst_pfnTextMessageGet_t ) ( const char ** ); -typedef void (*pfnEngDst_pfnDrawCharacter_t ) ( int *, int *, int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnDrawConsoleString_t ) ( int *, int *, char ** ); -typedef void (*pfnEngDst_pfnDrawSetTextColor_t ) ( float *, float *, float * ); -typedef void (*pfnEngDst_pfnDrawConsoleStringLen_t ) ( const char **, int **, int ** ); -typedef void (*pfnEngDst_pfnConsolePrint_t ) ( const char ** ); -typedef void (*pfnEngDst_pfnCenterPrint_t ) ( const char ** ); -typedef void (*pfnEngDst_GetWindowCenterX_t ) ( void ); -typedef void (*pfnEngDst_GetWindowCenterY_t ) ( void ); -typedef void (*pfnEngDst_GetViewAngles_t ) ( float ** ); -typedef void (*pfnEngDst_SetViewAngles_t ) ( float ** ); -typedef void (*pfnEngDst_GetMaxClients_t ) ( void ); -typedef void (*pfnEngDst_Cvar_SetValue_t ) ( char **, float * ); -typedef void (*pfnEngDst_Cmd_Argc_t) (void); -typedef void (*pfnEngDst_Cmd_Argv_t ) ( int * ); -typedef void (*pfnEngDst_Con_Printf_t ) ( char **); -typedef void (*pfnEngDst_Con_DPrintf_t ) ( char **); -typedef void (*pfnEngDst_Con_NPrintf_t ) ( int *, char ** ); -typedef void (*pfnEngDst_Con_NXPrintf_t ) ( struct con_nprint_s **, char **); -typedef void (*pfnEngDst_PhysInfo_ValueForKey_t ) ( const char ** ); -typedef void (*pfnEngDst_ServerInfo_ValueForKey_t ) ( const char ** ); -typedef void (*pfnEngDst_GetClientMaxspeed_t ) ( void ); -typedef void (*pfnEngDst_CheckParm_t ) ( char **, char *** ); -typedef void (*pfnEngDst_Key_Event_t ) ( int *, int * ); -typedef void (*pfnEngDst_GetMousePosition_t ) ( int **, int ** ); -typedef void (*pfnEngDst_IsNoClipping_t ) ( void ); -typedef void (*pfnEngDst_GetLocalPlayer_t ) ( void ); -typedef void (*pfnEngDst_GetViewModel_t ) ( void ); -typedef void (*pfnEngDst_GetEntityByIndex_t ) ( int * ); -typedef void (*pfnEngDst_GetClientTime_t ) ( void ); -typedef void (*pfnEngDst_V_CalcShake_t ) ( void ); -typedef void (*pfnEngDst_V_ApplyShake_t ) ( float **, float **, float * ); -typedef void (*pfnEngDst_PM_PointContents_t ) ( float **, int ** ); -typedef void (*pfnEngDst_PM_WaterEntity_t ) ( float ** ); -typedef void (*pfnEngDst_PM_TraceLine_t ) ( float **, float **, int *, int *, int * ); -typedef void (*pfnEngDst_CL_LoadModel_t ) ( const char **, int ** ); -typedef void (*pfnEngDst_CL_CreateVisibleEntity_t ) ( int *, struct cl_entity_s ** ); -typedef void (*pfnEngDst_GetSpritePointer_t ) ( HLSPRITE * ); -typedef void (*pfnEngDst_pfnPlaySoundByNameAtLocation_t ) ( char **, float *, float ** ); -typedef void (*pfnEngDst_pfnPrecacheEvent_t ) ( int *, const char* * ); -typedef void (*pfnEngDst_pfnPlaybackEvent_t ) ( int *, const struct edict_s **, unsigned short *, float *, float **, float **, float *, float *, int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnWeaponAnim_t ) ( int *, int * ); -typedef void (*pfnEngDst_pfnRandomFloat_t ) ( float *, float * ); -typedef void (*pfnEngDst_pfnRandomLong_t ) ( int32 *, int32 * ); -typedef void (*pfnEngDst_pfnHookEvent_t ) ( char **, void ( **pfnEvent )( struct event_args_s *args ) ); -typedef void (*pfnEngDst_Con_IsVisible_t) (); -typedef void (*pfnEngDst_pfnGetGameDirectory_t ) ( void ); -typedef void (*pfnEngDst_pfnGetCvarPointer_t ) ( const char ** ); -typedef void (*pfnEngDst_Key_LookupBinding_t ) ( const char ** ); -typedef void (*pfnEngDst_pfnGetLevelName_t ) ( void ); -typedef void (*pfnEngDst_pfnGetScreenFade_t ) ( struct screenfade_s ** ); -typedef void (*pfnEngDst_pfnSetScreenFade_t ) ( struct screenfade_s ** ); -typedef void (*pfnEngDst_VGui_GetPanel_t ) ( ); -typedef void (*pfnEngDst_VGui_ViewportPaintBackground_t ) (int **); -typedef void (*pfnEngDst_COM_LoadFile_t ) ( char **, int *, int ** ); -typedef void (*pfnEngDst_COM_ParseFile_t ) ( char **, char ** ); -typedef void (*pfnEngDst_COM_FreeFile_t) ( void ** ); -typedef void (*pfnEngDst_IsSpectateOnly_t ) ( void ); -typedef void (*pfnEngDst_LoadMapSprite_t ) ( const char ** ); -typedef void (*pfnEngDst_COM_AddAppDirectoryToSearchPath_t ) ( const char **, const char ** ); -typedef void (*pfnEngDst_COM_ExpandFilename_t) ( const char **, char **, int * ); -typedef void (*pfnEngDst_PlayerInfo_ValueForKey_t ) ( int *, const char ** ); -typedef void (*pfnEngDst_PlayerInfo_SetValueForKey_t )( const char **, const char ** ); -typedef void (*pfnEngDst_GetPlayerUniqueID_t) (int *, char **); -typedef void (*pfnEngDst_GetTrackerIDForPlayer_t) (int *); -typedef void (*pfnEngDst_GetPlayerForTrackerID_t) (int *); -typedef void (*pfnEngDst_pfnServerCmdUnreliable_t ) ( char ** ); -typedef void (*pfnEngDst_GetMousePos_t ) (struct tagPOINT **); -typedef void (*pfnEngDst_SetMousePos_t ) (int *, int *); -typedef void (*pfnEngDst_SetMouseEnable_t ) (qboolean *); -typedef void (*pfnEngDst_pfnSetFilterMode_t) ( int * ); -typedef void (*pfnEngDst_pfnSetFilterColor_t) ( float *, float *, float * ); -typedef void (*pfnEngDst_pfnSetFilterBrightness_t) ( float * ); -typedef void (*pfnEngDst_pfnSequenceGet_t ) ( const char**, const char** ); -typedef void (*pfnEngDst_pfnSPR_DrawGeneric_t ) ( int *, int *, int *, const struct rect_s **, int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnSequencePickSentence_t ) ( const char**, int *, int ** ); -typedef void (*pfnEngDst_pfnDrawString_t ) ( int *, int *, const char *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnDrawStringReverse_t ) ( int *, int *, const char *, int *, int *, int * ); -typedef void (*pfnEngDst_LocalPlayerInfo_ValueForKey_t )( const char **); -typedef void (*pfnEngDst_pfnVGUI2DrawCharacter_t ) ( int *, int *, int *, unsigned int * ); -typedef void (*pfnEngDst_pfnVGUI2DrawCharacterAdd_t ) ( int *, int *, int *, int *, int *, int *, unsigned int *); -typedef void (*pfnEngDst_pfnProcessTutorMessageDecayBuffer_t )(int **, int *); -typedef void (*pfnEngDst_pfnConstructTutorMessageDecayBuffer_t )(int **, int *); -typedef void (*pfnEngDst_pfnResetTutorMessageDecayData_t)(); -typedef void (*pfnEngDst_pfnFillRGBABlend_t ) ( int *, int *, int *, int *, int *, int *, int *, int * ); -typedef void (*pfnEngDst_pfnGetAppID_t ) ( void ); -typedef void (*pfnEngDst_pfnGetAliases_t ) ( void ); -typedef void (*pfnEngDst_pfnVguiWrap2_GetMouseDelta_t) ( int *x, int *y ); - - -// Pointers to the engine destination functions -typedef struct -{ - pfnEngDst_pfnSPR_Load_t pfnSPR_Load; - pfnEngDst_pfnSPR_Frames_t pfnSPR_Frames; - pfnEngDst_pfnSPR_Height_t pfnSPR_Height; - pfnEngDst_pfnSPR_Width_t pfnSPR_Width; - pfnEngDst_pfnSPR_Set_t pfnSPR_Set; - pfnEngDst_pfnSPR_Draw_t pfnSPR_Draw; - pfnEngDst_pfnSPR_DrawHoles_t pfnSPR_DrawHoles; - pfnEngDst_pfnSPR_DrawAdditive_t pfnSPR_DrawAdditive; - pfnEngDst_pfnSPR_EnableScissor_t pfnSPR_EnableScissor; - pfnEngDst_pfnSPR_DisableScissor_t pfnSPR_DisableScissor; - pfnEngDst_pfnSPR_GetList_t pfnSPR_GetList; - pfnEngDst_pfnFillRGBA_t pfnFillRGBA; - pfnEngDst_pfnGetScreenInfo_t pfnGetScreenInfo; - pfnEngDst_pfnSetCrosshair_t pfnSetCrosshair; - pfnEngDst_pfnRegisterVariable_t pfnRegisterVariable; - pfnEngDst_pfnGetCvarFloat_t pfnGetCvarFloat; - pfnEngDst_pfnGetCvarString_t pfnGetCvarString; - pfnEngDst_pfnAddCommand_t pfnAddCommand; - pfnEngDst_pfnHookUserMsg_t pfnHookUserMsg; - pfnEngDst_pfnServerCmd_t pfnServerCmd; - pfnEngDst_pfnClientCmd_t pfnClientCmd; - pfnEngDst_pfnGetPlayerInfo_t pfnGetPlayerInfo; - pfnEngDst_pfnPlaySoundByName_t pfnPlaySoundByName; - pfnEngDst_pfnPlaySoundByIndex_t pfnPlaySoundByIndex; - pfnEngDst_pfnAngleVectors_t pfnAngleVectors; - pfnEngDst_pfnTextMessageGet_t pfnTextMessageGet; - pfnEngDst_pfnDrawCharacter_t pfnDrawCharacter; - pfnEngDst_pfnDrawConsoleString_t pfnDrawConsoleString; - pfnEngDst_pfnDrawSetTextColor_t pfnDrawSetTextColor; - pfnEngDst_pfnDrawConsoleStringLen_t pfnDrawConsoleStringLen; - pfnEngDst_pfnConsolePrint_t pfnConsolePrint; - pfnEngDst_pfnCenterPrint_t pfnCenterPrint; - pfnEngDst_GetWindowCenterX_t GetWindowCenterX; - pfnEngDst_GetWindowCenterY_t GetWindowCenterY; - pfnEngDst_GetViewAngles_t GetViewAngles; - pfnEngDst_SetViewAngles_t SetViewAngles; - pfnEngDst_GetMaxClients_t GetMaxClients; - pfnEngDst_Cvar_SetValue_t Cvar_SetValue; - pfnEngDst_Cmd_Argc_t Cmd_Argc; - pfnEngDst_Cmd_Argv_t Cmd_Argv; - pfnEngDst_Con_Printf_t Con_Printf; - pfnEngDst_Con_DPrintf_t Con_DPrintf; - pfnEngDst_Con_NPrintf_t Con_NPrintf; - pfnEngDst_Con_NXPrintf_t Con_NXPrintf; - pfnEngDst_PhysInfo_ValueForKey_t PhysInfo_ValueForKey; - pfnEngDst_ServerInfo_ValueForKey_t ServerInfo_ValueForKey; - pfnEngDst_GetClientMaxspeed_t GetClientMaxspeed; - pfnEngDst_CheckParm_t CheckParm; - pfnEngDst_Key_Event_t Key_Event; - pfnEngDst_GetMousePosition_t GetMousePosition; - pfnEngDst_IsNoClipping_t IsNoClipping; - pfnEngDst_GetLocalPlayer_t GetLocalPlayer; - pfnEngDst_GetViewModel_t GetViewModel; - pfnEngDst_GetEntityByIndex_t GetEntityByIndex; - pfnEngDst_GetClientTime_t GetClientTime; - pfnEngDst_V_CalcShake_t V_CalcShake; - pfnEngDst_V_ApplyShake_t V_ApplyShake; - pfnEngDst_PM_PointContents_t PM_PointContents; - pfnEngDst_PM_WaterEntity_t PM_WaterEntity; - pfnEngDst_PM_TraceLine_t PM_TraceLine; - pfnEngDst_CL_LoadModel_t CL_LoadModel; - pfnEngDst_CL_CreateVisibleEntity_t CL_CreateVisibleEntity; - pfnEngDst_GetSpritePointer_t GetSpritePointer; - pfnEngDst_pfnPlaySoundByNameAtLocation_t pfnPlaySoundByNameAtLocation; - pfnEngDst_pfnPrecacheEvent_t pfnPrecacheEvent; - pfnEngDst_pfnPlaybackEvent_t pfnPlaybackEvent; - pfnEngDst_pfnWeaponAnim_t pfnWeaponAnim; - pfnEngDst_pfnRandomFloat_t pfnRandomFloat; - pfnEngDst_pfnRandomLong_t pfnRandomLong; - pfnEngDst_pfnHookEvent_t pfnHookEvent; - pfnEngDst_Con_IsVisible_t Con_IsVisible; - pfnEngDst_pfnGetGameDirectory_t pfnGetGameDirectory; - pfnEngDst_pfnGetCvarPointer_t pfnGetCvarPointer; - pfnEngDst_Key_LookupBinding_t Key_LookupBinding; - pfnEngDst_pfnGetLevelName_t pfnGetLevelName; - pfnEngDst_pfnGetScreenFade_t pfnGetScreenFade; - pfnEngDst_pfnSetScreenFade_t pfnSetScreenFade; - pfnEngDst_VGui_GetPanel_t VGui_GetPanel; - pfnEngDst_VGui_ViewportPaintBackground_t VGui_ViewportPaintBackground; - pfnEngDst_COM_LoadFile_t COM_LoadFile; - pfnEngDst_COM_ParseFile_t COM_ParseFile; - pfnEngDst_COM_FreeFile_t COM_FreeFile; - struct triangleapi_s *pTriAPI; - struct efx_api_s *pEfxAPI; - struct event_api_s *pEventAPI; - struct demo_api_s *pDemoAPI; - struct net_api_s *pNetAPI; - struct IVoiceTweak_s *pVoiceTweak; - pfnEngDst_IsSpectateOnly_t IsSpectateOnly; - pfnEngDst_LoadMapSprite_t LoadMapSprite; - pfnEngDst_COM_AddAppDirectoryToSearchPath_t COM_AddAppDirectoryToSearchPath; - pfnEngDst_COM_ExpandFilename_t COM_ExpandFilename; - pfnEngDst_PlayerInfo_ValueForKey_t PlayerInfo_ValueForKey; - pfnEngDst_PlayerInfo_SetValueForKey_t PlayerInfo_SetValueForKey; - pfnEngDst_GetPlayerUniqueID_t GetPlayerUniqueID; - pfnEngDst_GetTrackerIDForPlayer_t GetTrackerIDForPlayer; - pfnEngDst_GetPlayerForTrackerID_t GetPlayerForTrackerID; - pfnEngDst_pfnServerCmdUnreliable_t pfnServerCmdUnreliable; - pfnEngDst_GetMousePos_t pfnGetMousePos; - pfnEngDst_SetMousePos_t pfnSetMousePos; - pfnEngDst_SetMouseEnable_t pfnSetMouseEnable; - pfnEngDst_pfnSetFilterMode_t pfnSetFilterMode ; - pfnEngDst_pfnSetFilterColor_t pfnSetFilterColor ; - pfnEngDst_pfnSetFilterBrightness_t pfnSetFilterBrightness ; - pfnEngDst_pfnSequenceGet_t pfnSequenceGet; - pfnEngDst_pfnSPR_DrawGeneric_t pfnSPR_DrawGeneric; - pfnEngDst_pfnSequencePickSentence_t pfnSequencePickSentence; - pfnEngDst_pfnDrawString_t pfnDrawString; - pfnEngDst_pfnDrawString_t pfnDrawStringReverse; - pfnEngDst_LocalPlayerInfo_ValueForKey_t LocalPlayerInfo_ValueForKey; - pfnEngDst_pfnVGUI2DrawCharacter_t pfnVGUI2DrawCharacter; - pfnEngDst_pfnVGUI2DrawCharacterAdd_t pfnVGUI2DrawCharacterAdd; - pfnEngDst_pfnPlaySoundVoiceByName_t pfnPlaySoundVoiceByName; - pfnEngDst_pfnPrimeMusicStream_t pfnPrimeMusicStream; - pfnEngDst_pfnProcessTutorMessageDecayBuffer_t pfnProcessTutorMessageDecayBuffer; - pfnEngDst_pfnConstructTutorMessageDecayBuffer_t pfnConstructTutorMessageDecayBuffer; - pfnEngDst_pfnResetTutorMessageDecayData_t pfnResetTutorMessageDecayData; - pfnEngDst_pfnPlaySoundByNameAtPitch_t pfnPlaySoundByNameAtPitch; - pfnEngDst_pfnFillRGBABlend_t pfnFillRGBABlend; - pfnEngDst_pfnGetAppID_t pfnGetAppID; - pfnEngDst_pfnGetAliases_t pfnGetAliasList; - pfnEngDst_pfnVguiWrap2_GetMouseDelta_t pfnVguiWrap2_GetMouseDelta; -} cl_enginefunc_dst_t; - - -// ******************************************************** -// Functions exposed by the engine to the module -// ******************************************************** - -// Functions for ModuleS -typedef void (*PFN_KICKPLAYER)(int nPlayerSlot, int nReason); - -typedef struct modshelpers_s -{ - PFN_KICKPLAYER m_pfnKickPlayer; - - // reserved for future expansion - int m_nVoid1; - int m_nVoid2; - int m_nVoid3; - int m_nVoid4; - int m_nVoid5; - int m_nVoid6; - int m_nVoid7; - int m_nVoid8; - int m_nVoid9; -} modshelpers_t; - -// Functions for moduleC -typedef struct modchelpers_s -{ - // reserved for future expansion - int m_nVoid0; - int m_nVoid1; - int m_nVoid2; - int m_nVoid3; - int m_nVoid4; - int m_nVoid5; - int m_nVoid6; - int m_nVoid7; - int m_nVoid8; - int m_nVoid9; -} modchelpers_t; - - -// ******************************************************** -// Information about the engine -// ******************************************************** -typedef struct engdata_s -{ - cl_enginefunc_t *pcl_enginefuncs; // functions exported by the engine - cl_enginefunc_dst_t *pg_engdstAddrs; // destination handlers for engine exports - cldll_func_t *pcl_funcs; // client exports - cldll_func_dst_t *pg_cldstAddrs; // client export destination handlers - struct modfuncs_s *pg_modfuncs; // engine's pointer to module functions - struct cmd_function_s **pcmd_functions; // list of all registered commands - void *pkeybindings; // all key bindings (not really a void *, but easier this way) - void (*pfnConPrintf)(char *, ...); // dump to console - struct cvar_s **pcvar_vars; // pointer to head of cvar list - struct glwstate_t *pglwstate; // OpenGl information - void *(*pfnSZ_GetSpace)(struct sizebuf_s *, int); // pointer to SZ_GetSpace - struct modfuncs_s *pmodfuncs; // &g_modfuncs - void *pfnGetProcAddress; // &GetProcAddress - void *pfnGetModuleHandle; // &GetModuleHandle - struct server_static_s *psvs; // &svs - struct client_static_s *pcls; // &cls - void (*pfnSV_DropClient)(struct client_s *, qboolean, char *, ...); // pointer to SV_DropClient - void (*pfnNetchan_Transmit)(struct netchan_s *, int, byte *); // pointer to Netchan_Transmit - void (*pfnNET_SendPacket)(enum netsrc_s sock, int length, void *data, netadr_t to); // &NET_SendPacket - struct cvar_s *(*pfnCvarFindVar)(const char *pchName); // pointer to Cvar_FindVar - int *phinstOpenGlEarly; // &g_hinstOpenGlEarly - - // Reserved for future expansion - void *pVoid0; // reserved for future expan - void *pVoid1; // reserved for future expan - void *pVoid2; // reserved for future expan - void *pVoid3; // reserved for future expan - void *pVoid4; // reserved for future expan - void *pVoid5; // reserved for future expan - void *pVoid6; // reserved for future expan - void *pVoid7; // reserved for future expan - void *pVoid8; // reserved for future expan - void *pVoid9; // reserved for future expan -} engdata_t; - - -// ******************************************************** -// Functions exposed by the security module -// ******************************************************** -typedef void (*PFN_LOADMOD)(char *pchModule); -typedef void (*PFN_CLOSEMOD)(void); -typedef int (*PFN_NCALL)(int ijump, int cnArg, ...); - -typedef void (*PFN_GETCLDSTADDRS)(cldll_func_dst_t *pcldstAddrs); -typedef void (*PFN_GETENGDSTADDRS)(cl_enginefunc_dst_t *pengdstAddrs); -typedef void (*PFN_MODULELOADED)(void); - -typedef void (*PFN_PROCESSOUTGOINGNET)(struct netchan_s *pchan, struct sizebuf_s *psizebuf); -typedef qboolean (*PFN_PROCESSINCOMINGNET)(struct netchan_s *pchan, struct sizebuf_s *psizebuf); - -typedef void (*PFN_TEXTURELOAD)(char *pszName, int dxWidth, int dyHeight, char *pbData); -typedef void (*PFN_MODELLOAD)(struct model_s *pmodel, void *pvBuf); - -typedef void (*PFN_FRAMEBEGIN)(void); -typedef void (*PFN_FRAMERENDER1)(void); -typedef void (*PFN_FRAMERENDER2)(void); - -typedef void (*PFN_SETMODSHELPERS)(modshelpers_t *pmodshelpers); -typedef void (*PFN_SETMODCHELPERS)(modchelpers_t *pmodchelpers); -typedef void (*PFN_SETENGDATA)(engdata_t *pengdata); - -typedef void (*PFN_CONNECTCLIENT)(int iPlayer); -typedef void (*PFN_RECORDIP)(unsigned int pnIP); -typedef void (*PFN_PLAYERSTATUS)(unsigned char *pbData, int cbData); - -typedef void (*PFN_SETENGINEVERSION)(int nVersion); - -// typedef class CMachine *(*PFN_PCMACHINE)(void); -typedef int (*PFN_PCMACHINE)(void); -typedef void (*PFN_SETIP)(int ijump); -typedef void (*PFN_EXECUTE)(void); - -typedef struct modfuncs_s -{ - // Functions for the pcode interpreter - PFN_LOADMOD m_pfnLoadMod; - PFN_CLOSEMOD m_pfnCloseMod; - PFN_NCALL m_pfnNCall; - - // API destination functions - PFN_GETCLDSTADDRS m_pfnGetClDstAddrs; - PFN_GETENGDSTADDRS m_pfnGetEngDstAddrs; - - // Miscellaneous functions - PFN_MODULELOADED m_pfnModuleLoaded; // Called right after the module is loaded - - // Functions for processing network traffic - PFN_PROCESSOUTGOINGNET m_pfnProcessOutgoingNet; // Every outgoing packet gets run through this - PFN_PROCESSINCOMINGNET m_pfnProcessIncomingNet; // Every incoming packet gets run through this - - // Resource functions - PFN_TEXTURELOAD m_pfnTextureLoad; // Called as each texture is loaded - PFN_MODELLOAD m_pfnModelLoad; // Called as each model is loaded - - // Functions called every frame - PFN_FRAMEBEGIN m_pfnFrameBegin; // Called at the beginning of each frame cycle - PFN_FRAMERENDER1 m_pfnFrameRender1; // Called at the beginning of the render loop - PFN_FRAMERENDER2 m_pfnFrameRender2; // Called at the end of the render loop - - // Module helper transfer - PFN_SETMODSHELPERS m_pfnSetModSHelpers; - PFN_SETMODCHELPERS m_pfnSetModCHelpers; - PFN_SETENGDATA m_pfnSetEngData; - - // Which version of the module is this? - int m_nVersion; - - // Miscellaneous game stuff - PFN_CONNECTCLIENT m_pfnConnectClient; // Called whenever a new client connects - PFN_RECORDIP m_pfnRecordIP; // Secure master has reported a new IP for us - PFN_PLAYERSTATUS m_pfnPlayerStatus; // Called whenever we receive a PlayerStatus packet - - // Recent additions - PFN_SETENGINEVERSION m_pfnSetEngineVersion; // 1 = patched engine - - // reserved for future expansion - int m_nVoid2; - int m_nVoid3; - int m_nVoid4; - int m_nVoid5; - int m_nVoid6; - int m_nVoid7; - int m_nVoid8; - int m_nVoid9; -} modfuncs_t; - - -#define k_nEngineVersion15Base 0 -#define k_nEngineVersion15Patch 1 -#define k_nEngineVersion16Base 2 -#define k_nEngineVersion16Validated 3 // 1.6 engine with built-in validation - - -typedef struct validator_s -{ - int m_nRandomizer; // Random number to be XOR'd into all subsequent fields - int m_nSignature1; // First signature that identifies this structure - int m_nSignature2; // Second signature - int m_pbCode; // Beginning of the code block - int m_cbCode; // Size of the code block - int m_nChecksum; // Checksum of the code block - int m_nSpecial; // For engine, 1 if hw.dll, 0 if sw.dll. For client, pclfuncs checksum - int m_nCompensator; // Keeps the checksum correct -} validator_t; - - -#define k_nChecksumCompensator 0x36a8f09c // Don't change this value: it's hardcorded in cdll_int.cpp, - -#define k_nModuleVersionCur 0x43210004 - - -#endif // __APIPROXY__ diff --git a/sdk/engine/anorms.h b/sdk/engine/anorms.h deleted file mode 100644 index d147aea..0000000 --- a/sdk/engine/anorms.h +++ /dev/null @@ -1,177 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -{-0.525731, 0.000000, 0.850651}, -{-0.442863, 0.238856, 0.864188}, -{-0.295242, 0.000000, 0.955423}, -{-0.309017, 0.500000, 0.809017}, -{-0.162460, 0.262866, 0.951056}, -{0.000000, 0.000000, 1.000000}, -{0.000000, 0.850651, 0.525731}, -{-0.147621, 0.716567, 0.681718}, -{0.147621, 0.716567, 0.681718}, -{0.000000, 0.525731, 0.850651}, -{0.309017, 0.500000, 0.809017}, -{0.525731, 0.000000, 0.850651}, -{0.295242, 0.000000, 0.955423}, -{0.442863, 0.238856, 0.864188}, -{0.162460, 0.262866, 0.951056}, -{-0.681718, 0.147621, 0.716567}, -{-0.809017, 0.309017, 0.500000}, -{-0.587785, 0.425325, 0.688191}, -{-0.850651, 0.525731, 0.000000}, -{-0.864188, 0.442863, 0.238856}, -{-0.716567, 0.681718, 0.147621}, -{-0.688191, 0.587785, 0.425325}, -{-0.500000, 0.809017, 0.309017}, -{-0.238856, 0.864188, 0.442863}, -{-0.425325, 0.688191, 0.587785}, -{-0.716567, 0.681718, -0.147621}, -{-0.500000, 0.809017, -0.309017}, -{-0.525731, 0.850651, 0.000000}, -{0.000000, 0.850651, -0.525731}, -{-0.238856, 0.864188, -0.442863}, -{0.000000, 0.955423, -0.295242}, -{-0.262866, 0.951056, -0.162460}, -{0.000000, 1.000000, 0.000000}, -{0.000000, 0.955423, 0.295242}, -{-0.262866, 0.951056, 0.162460}, -{0.238856, 0.864188, 0.442863}, -{0.262866, 0.951056, 0.162460}, -{0.500000, 0.809017, 0.309017}, -{0.238856, 0.864188, -0.442863}, -{0.262866, 0.951056, -0.162460}, -{0.500000, 0.809017, -0.309017}, -{0.850651, 0.525731, 0.000000}, -{0.716567, 0.681718, 0.147621}, -{0.716567, 0.681718, -0.147621}, -{0.525731, 0.850651, 0.000000}, -{0.425325, 0.688191, 0.587785}, -{0.864188, 0.442863, 0.238856}, -{0.688191, 0.587785, 0.425325}, -{0.809017, 0.309017, 0.500000}, -{0.681718, 0.147621, 0.716567}, -{0.587785, 0.425325, 0.688191}, -{0.955423, 0.295242, 0.000000}, -{1.000000, 0.000000, 0.000000}, -{0.951056, 0.162460, 0.262866}, -{0.850651, -0.525731, 0.000000}, -{0.955423, -0.295242, 0.000000}, -{0.864188, -0.442863, 0.238856}, -{0.951056, -0.162460, 0.262866}, -{0.809017, -0.309017, 0.500000}, -{0.681718, -0.147621, 0.716567}, -{0.850651, 0.000000, 0.525731}, -{0.864188, 0.442863, -0.238856}, -{0.809017, 0.309017, -0.500000}, -{0.951056, 0.162460, -0.262866}, -{0.525731, 0.000000, -0.850651}, -{0.681718, 0.147621, -0.716567}, -{0.681718, -0.147621, -0.716567}, -{0.850651, 0.000000, -0.525731}, -{0.809017, -0.309017, -0.500000}, -{0.864188, -0.442863, -0.238856}, -{0.951056, -0.162460, -0.262866}, -{0.147621, 0.716567, -0.681718}, -{0.309017, 0.500000, -0.809017}, -{0.425325, 0.688191, -0.587785}, -{0.442863, 0.238856, -0.864188}, -{0.587785, 0.425325, -0.688191}, -{0.688191, 0.587785, -0.425325}, -{-0.147621, 0.716567, -0.681718}, -{-0.309017, 0.500000, -0.809017}, -{0.000000, 0.525731, -0.850651}, -{-0.525731, 0.000000, -0.850651}, -{-0.442863, 0.238856, -0.864188}, -{-0.295242, 0.000000, -0.955423}, -{-0.162460, 0.262866, -0.951056}, -{0.000000, 0.000000, -1.000000}, -{0.295242, 0.000000, -0.955423}, -{0.162460, 0.262866, -0.951056}, -{-0.442863, -0.238856, -0.864188}, -{-0.309017, -0.500000, -0.809017}, -{-0.162460, -0.262866, -0.951056}, -{0.000000, -0.850651, -0.525731}, -{-0.147621, -0.716567, -0.681718}, -{0.147621, -0.716567, -0.681718}, -{0.000000, -0.525731, -0.850651}, -{0.309017, -0.500000, -0.809017}, -{0.442863, -0.238856, -0.864188}, -{0.162460, -0.262866, -0.951056}, -{0.238856, -0.864188, -0.442863}, -{0.500000, -0.809017, -0.309017}, -{0.425325, -0.688191, -0.587785}, -{0.716567, -0.681718, -0.147621}, -{0.688191, -0.587785, -0.425325}, -{0.587785, -0.425325, -0.688191}, -{0.000000, -0.955423, -0.295242}, -{0.000000, -1.000000, 0.000000}, -{0.262866, -0.951056, -0.162460}, -{0.000000, -0.850651, 0.525731}, -{0.000000, -0.955423, 0.295242}, -{0.238856, -0.864188, 0.442863}, -{0.262866, -0.951056, 0.162460}, -{0.500000, -0.809017, 0.309017}, -{0.716567, -0.681718, 0.147621}, -{0.525731, -0.850651, 0.000000}, -{-0.238856, -0.864188, -0.442863}, -{-0.500000, -0.809017, -0.309017}, -{-0.262866, -0.951056, -0.162460}, -{-0.850651, -0.525731, 0.000000}, -{-0.716567, -0.681718, -0.147621}, -{-0.716567, -0.681718, 0.147621}, -{-0.525731, -0.850651, 0.000000}, -{-0.500000, -0.809017, 0.309017}, -{-0.238856, -0.864188, 0.442863}, -{-0.262866, -0.951056, 0.162460}, -{-0.864188, -0.442863, 0.238856}, -{-0.809017, -0.309017, 0.500000}, -{-0.688191, -0.587785, 0.425325}, -{-0.681718, -0.147621, 0.716567}, -{-0.442863, -0.238856, 0.864188}, -{-0.587785, -0.425325, 0.688191}, -{-0.309017, -0.500000, 0.809017}, -{-0.147621, -0.716567, 0.681718}, -{-0.425325, -0.688191, 0.587785}, -{-0.162460, -0.262866, 0.951056}, -{0.442863, -0.238856, 0.864188}, -{0.162460, -0.262866, 0.951056}, -{0.309017, -0.500000, 0.809017}, -{0.147621, -0.716567, 0.681718}, -{0.000000, -0.525731, 0.850651}, -{0.425325, -0.688191, 0.587785}, -{0.587785, -0.425325, 0.688191}, -{0.688191, -0.587785, 0.425325}, -{-0.955423, 0.295242, 0.000000}, -{-0.951056, 0.162460, 0.262866}, -{-1.000000, 0.000000, 0.000000}, -{-0.850651, 0.000000, 0.525731}, -{-0.955423, -0.295242, 0.000000}, -{-0.951056, -0.162460, 0.262866}, -{-0.864188, 0.442863, -0.238856}, -{-0.951056, 0.162460, -0.262866}, -{-0.809017, 0.309017, -0.500000}, -{-0.864188, -0.442863, -0.238856}, -{-0.951056, -0.162460, -0.262866}, -{-0.809017, -0.309017, -0.500000}, -{-0.681718, 0.147621, -0.716567}, -{-0.681718, -0.147621, -0.716567}, -{-0.850651, 0.000000, -0.525731}, -{-0.688191, 0.587785, -0.425325}, -{-0.587785, 0.425325, -0.688191}, -{-0.425325, 0.688191, -0.587785}, -{-0.425325, -0.688191, -0.587785}, -{-0.587785, -0.425325, -0.688191}, -{-0.688191, -0.587785, -0.425325}, diff --git a/sdk/engine/archtypes.h b/sdk/engine/archtypes.h deleted file mode 100644 index 3315135..0000000 --- a/sdk/engine/archtypes.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Word size dependent definitions -// DAL 1/03 -// -#ifndef ARCHTYPES_H -#define ARCHTYPES_H - -#ifdef __x86_64__ -#define X64BITS -#endif - -#if defined( _WIN32 ) && (! defined( __MINGW32__ )) - -typedef __int16 int16; -typedef unsigned __int16 uint16; -typedef __int32 int32; -typedef unsigned __int32 uint32; -typedef __int64 int64; -typedef unsigned __int64 uint64; -typedef __int32 intp; // intp is an integer that can accomodate a pointer -typedef unsigned __int32 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) - -#else /* _WIN32 */ - -typedef short int16; -typedef unsigned short uint16; -typedef int int32; -typedef unsigned int uint32; -typedef long long int64; -typedef unsigned long long uint64; -#ifdef X64BITS -typedef long long intp; -typedef unsigned long long uintp; -#else -typedef int intp; -typedef unsigned int uintp; -#endif - -#endif /* else _WIN32 */ - -#endif /* ARCHTYPES_H */ diff --git a/sdk/engine/cdll_int.h b/sdk/engine/cdll_int.h deleted file mode 100644 index 9efd1fe..0000000 --- a/sdk/engine/cdll_int.h +++ /dev/null @@ -1,467 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// cdll_int.h -// -// 4-23-98 -// JOHN: client dll interface declarations -// - -#ifndef CDLL_INT_H -#define CDLL_INT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "const.h" -#include "steam/steamtypes.h" -#include "ref_params.h" -#include "r_efx.h" -#include "studio_event.h" - -// this file is included by both the engine and the client-dll, -// so make sure engine declarations aren't done twice - -typedef int HLSPRITE; // handle to a graphic - -#define SCRINFO_SCREENFLASH 1 -#define SCRINFO_STRETCHED 2 - -typedef struct SCREENINFO_s -{ - int iSize; - int iWidth; - int iHeight; - int iFlags; - int iCharHeight; - short charWidths[256]; -} SCREENINFO; - - -typedef struct client_data_s -{ - // fields that cannot be modified (ie. have no effect if changed) - vec3_t origin; - - // fields that can be changed by the cldll - vec3_t viewangles; - int iWeaponBits; -// int iAccessoryBits; - float fov; // field of view -} client_data_t; - -typedef struct client_sprite_s -{ - char szName[64]; - char szSprite[64]; - int hspr; - int iRes; - wrect_t rc; -} client_sprite_t; - - - -typedef struct hud_player_info_s -{ - char *name; - short ping; - byte thisplayer; // TRUE if this is the calling player - - byte spectator; - byte packetloss; - - char *model; - short topcolor; - short bottomcolor; - - uint64 m_nSteamID; -} hud_player_info_t; - - - -typedef struct module_s -{ - unsigned char ucMD5Hash[16]; // hash over code - qboolean fLoaded; // true if successfully loaded -} module_t; - - - - - - -#ifndef IN_BUTTONS_H -#include "in_buttons.h" -#endif - -#define CLDLL_INTERFACE_VERSION 7 - -extern void LoadSecurityModuleFromDisk(char * pszDllName); -extern void LoadSecurityModuleFromMemory( unsigned char * pCode, int nSize ); -extern void CloseSecurityModule(); - - -extern void ClientDLL_Init( void ); // from cdll_int.c -extern void ClientDLL_Shutdown( void ); -extern void ClientDLL_HudInit( void ); -extern void ClientDLL_HudVidInit( void ); -extern void ClientDLL_UpdateClientData( void ); -extern void ClientDLL_Frame( double time ); -extern void ClientDLL_HudRedraw( int intermission ); -extern void ClientDLL_MoveClient( struct playermove_s *ppmove ); -extern void ClientDLL_ClientMoveInit( struct playermove_s *ppmove ); -extern char ClientDLL_ClientTextureType( char *name ); - -extern void ClientDLL_CreateMove( float frametime, struct usercmd_s *cmd, int active ); -extern void ClientDLL_ActivateMouse( void ); -extern void ClientDLL_DeactivateMouse( void ); -extern void ClientDLL_MouseEvent( int mstate ); -extern void ClientDLL_ClearStates( void ); -extern int ClientDLL_IsThirdPerson( void ); -extern void ClientDLL_GetCameraOffsets( float *ofs ); -extern int ClientDLL_GraphKeyDown( void ); -extern struct kbutton_s *ClientDLL_FindKey( const char *name ); -extern void ClientDLL_CAM_Think( void ); -extern void ClientDLL_IN_Accumulate( void ); -extern void ClientDLL_CalcRefdef( struct ref_params_s *pparams ); -extern int ClientDLL_AddEntity( int type, struct cl_entity_s *ent ); -extern void ClientDLL_CreateEntities( void ); - -extern void ClientDLL_DrawNormalTriangles( void ); -extern void ClientDLL_DrawTransparentTriangles( void ); -extern void ClientDLL_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); -extern void ClientDLL_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); -extern void ClientDLL_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); -extern void ClientDLL_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); -extern void ClientDLL_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); -extern void ClientDLL_ReadDemoBuffer( int size, unsigned char *buffer ); -extern int ClientDLL_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); -extern int ClientDLL_GetHullBounds( int hullnumber, float *mins, float *maxs ); - -extern void ClientDLL_VGui_ConsolePrint(const char* text); - -extern int ClientDLL_Key_Event( int down, int keynum, const char *pszCurrentBinding ); -extern void ClientDLL_TempEntUpdate( double ft, double ct, double grav, struct tempent_s **ppFreeTE, struct tempent_s **ppActiveTE, int ( *addTEntity )( struct cl_entity_s *pEntity ), void ( *playTESound )( struct tempent_s *pTemp, float damp ) ); -extern struct cl_entity_s *ClientDLL_GetUserEntity( int index ); -extern void ClientDLL_VoiceStatus(int entindex, qboolean bTalking); -extern void ClientDLL_DirectorMessage( int iSize, void *pbuf ); -extern void ClientDLL_ChatInputPosition( int *x, int *y ); - -//#include "server.h" // server_static_t define for apiproxy -#include "APIProxy.h" - -extern cldll_func_t cl_funcs; -extern cl_enginefunc_t cl_engsrcProxies; -extern cl_enginefunc_dst_t g_engdstAddrs; - -// Module exports -extern modfuncs_t g_modfuncs; -extern module_t g_module; - -// Macros for exported engine funcs -#define RecEngSPR_Load(a) (g_engdstAddrs.pfnSPR_Load(&a)) -#define RecEngSPR_Frames(a) (g_engdstAddrs.pfnSPR_Frames(&a)) -#define RecEngSPR_Height(a, b) (g_engdstAddrs.pfnSPR_Height(&a, &b)) -#define RecEngSPR_Width(a, b) (g_engdstAddrs.pfnSPR_Width(&a, &b)) -#define RecEngSPR_Set(a, b, c, d) (g_engdstAddrs.pfnSPR_Set(&a, &b, &c, &d)) -#define RecEngSPR_Draw(a, b, c, d) (g_engdstAddrs.pfnSPR_Draw(&a, &b, &c, &d)) -#define RecEngSPR_DrawHoles(a, b, c, d) (g_engdstAddrs.pfnSPR_DrawHoles(&a, &b, &c, &d)) -#define RecEngSPR_DrawAdditive(a, b, c, d) (g_engdstAddrs.pfnSPR_DrawAdditive(&a, &b, &c, &d)) -#define RecEngSPR_EnableScissor(a, b, c, d) (g_engdstAddrs.pfnSPR_EnableScissor(&a, &b, &c, &d)) -#define RecEngSPR_DisableScissor() (g_engdstAddrs.pfnSPR_DisableScissor()) -#define RecEngSPR_GetList(a, b) (g_engdstAddrs.pfnSPR_GetList(&a, &b)) -#define RecEngDraw_FillRGBA(a, b, c, d, e, f, g, h) (g_engdstAddrs.pfnFillRGBA(&a, &b, &c, &d, &e, &f, &g, &h)) -#define RecEnghudGetScreenInfo(a) (g_engdstAddrs.pfnGetScreenInfo(&a)) -#define RecEngSetCrosshair(a, b, c, d, e) (g_engdstAddrs.pfnSetCrosshair(&a, &b, &c, &d, &e)) -#define RecEnghudRegisterVariable(a, b, c) (g_engdstAddrs.pfnRegisterVariable(&a, &b, &c)) -#define RecEnghudGetCvarFloat(a) (g_engdstAddrs.pfnGetCvarFloat(&a)) -#define RecEnghudGetCvarString(a) (g_engdstAddrs.pfnGetCvarString(&a)) -#define RecEnghudAddCommand(a, b) (g_engdstAddrs.pfnAddCommand(&a, &b)) -#define RecEnghudHookUserMsg(a, b) (g_engdstAddrs.pfnHookUserMsg(&a, &b)) -#define RecEnghudServerCmd(a) (g_engdstAddrs.pfnServerCmd(&a)) -#define RecEnghudClientCmd(a) (g_engdstAddrs.pfnClientCmd(&a)) -#define RecEngPrimeMusicStream(a, b) (g_engdstAddrs.pfnPrimeMusicStream(&a, &b)) -#define RecEnghudGetPlayerInfo(a, b) (g_engdstAddrs.pfnGetPlayerInfo(&a, &b)) -#define RecEnghudPlaySoundByName(a, b) (g_engdstAddrs.pfnPlaySoundByName(&a, &b)) -#define RecEnghudPlaySoundByNameAtPitch(a, b, c) (g_engdstAddrs.pfnPlaySoundByNameAtPitch(&a, &b, &c)) -#define RecEnghudPlaySoundVoiceByName(a, b) (g_engdstAddrs.pfnPlaySoundVoiceByName(&a, &b)) -#define RecEnghudPlaySoundByIndex(a, b) (g_engdstAddrs.pfnPlaySoundByIndex(&a, &b)) -#define RecEngAngleVectors(a, b, c, d) (g_engdstAddrs.pfnAngleVectors(&a, &b, &c, &d)) -#define RecEngTextMessageGet(a) (g_engdstAddrs.pfnTextMessageGet(&a)) -#define RecEngTextMessageDrawCharacter(a, b, c, d, e, f) (g_engdstAddrs.pfnDrawCharacter(&a, &b, &c, &d, &e, &f)) -#define RecEngDrawConsoleString(a, b, c) (g_engdstAddrs.pfnDrawConsoleString(&a, &b, &c)) -#define RecEngDrawSetTextColor(a, b, c) (g_engdstAddrs.pfnDrawSetTextColor(&a, &b, &c)) -#define RecEnghudDrawConsoleStringLen(a, b, c) (g_engdstAddrs.pfnDrawConsoleStringLen(&a, &b, &c)) -#define RecEnghudConsolePrint(a) (g_engdstAddrs.pfnConsolePrint(&a)) -#define RecEnghudCenterPrint(a) (g_engdstAddrs.pfnCenterPrint(&a)) -#define RecEnghudCenterX() (g_engdstAddrs.GetWindowCenterX()) -#define RecEnghudCenterY() (g_engdstAddrs.GetWindowCenterY()) -#define RecEnghudGetViewAngles(a) (g_engdstAddrs.GetViewAngles(&a)) -#define RecEnghudSetViewAngles(a) (g_engdstAddrs.SetViewAngles(&a)) -#define RecEnghudGetMaxClients() (g_engdstAddrs.GetMaxClients()) -#define RecEngCvar_SetValue(a, b) (g_engdstAddrs.Cvar_SetValue(&a, &b)) -#define RecEngCmd_Argc() (g_engdstAddrs.Cmd_Argc()) -#define RecEngCmd_Argv(a) (g_engdstAddrs.Cmd_Argv(&a)) -#define RecEngCon_Printf(a) (g_engdstAddrs.Con_Printf(&a)) -#define RecEngCon_DPrintf(a) (g_engdstAddrs.Con_DPrintf(&a)) -#define RecEngCon_NPrintf(a, b) (g_engdstAddrs.Con_NPrintf(&a, &b)) -#define RecEngCon_NXPrintf(a, b) (g_engdstAddrs.Con_NXPrintf(&a, &b)) -#define RecEnghudPhysInfo_ValueForKey(a) (g_engdstAddrs.PhysInfo_ValueForKey(&a)) -#define RecEnghudServerInfo_ValueForKey(a) (g_engdstAddrs.ServerInfo_ValueForKey(&a)) -#define RecEnghudGetClientMaxspeed() (g_engdstAddrs.GetClientMaxspeed()) -#define RecEnghudCheckParm(a, b) (g_engdstAddrs.CheckParm(&a, &b)) -#define RecEngKey_Event(a, b) (g_engdstAddrs.Key_Event(&a, &b)) -#define RecEnghudGetMousePosition(a, b) (g_engdstAddrs.GetMousePosition(&a, &b)) -#define RecEnghudIsNoClipping() (g_engdstAddrs.IsNoClipping()) -#define RecEnghudGetLocalPlayer() (g_engdstAddrs.GetLocalPlayer()) -#define RecEnghudGetViewModel() (g_engdstAddrs.GetViewModel()) -#define RecEnghudGetEntityByIndex(a) (g_engdstAddrs.GetEntityByIndex(&a)) -#define RecEnghudGetClientTime() (g_engdstAddrs.GetClientTime()) -#define RecEngV_CalcShake() (g_engdstAddrs.V_CalcShake()) -#define RecEngV_ApplyShake(a, b, c) (g_engdstAddrs.V_ApplyShake(&a, &b, &c)) -#define RecEngPM_PointContents(a, b) (g_engdstAddrs.PM_PointContents(&a, &b)) -#define RecEngPM_WaterEntity(a) (g_engdstAddrs.PM_WaterEntity(&a)) -#define RecEngPM_TraceLine(a, b, c, d, e) (g_engdstAddrs.PM_TraceLine(&a, &b, &c, &d, &e)) -#define RecEngCL_LoadModel(a, b) (g_engdstAddrs.CL_LoadModel(&a, &b)) -#define RecEngCL_CreateVisibleEntity(a, b) (g_engdstAddrs.CL_CreateVisibleEntity(&a, &b)) -#define RecEnghudGetSpritePointer(a) (g_engdstAddrs.GetSpritePointer(&a)) -#define RecEnghudPlaySoundByNameAtLocation(a, b, c) (g_engdstAddrs.pfnPlaySoundByNameAtLocation(&a, &b, &c)) -#define RecEnghudPrecacheEvent(a, b) (g_engdstAddrs.pfnPrecacheEvent(&a, &b)) -#define RecEnghudPlaybackEvent(a, b, c, d, e, f, g, h, i, j, k, l) (g_engdstAddrs.pfnPlaybackEvent(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l)) -#define RecEnghudWeaponAnim(a, b) (g_engdstAddrs.pfnWeaponAnim(&a, &b)) -#define RecEngRandomFloat(a, b) (g_engdstAddrs.pfnRandomFloat(&a, &b)) -#define RecEngRandomLong(a, b) (g_engdstAddrs.pfnRandomLong(&a, &b)) -#define RecEngCL_HookEvent(a, b) (g_engdstAddrs.pfnHookEvent(&a, &b)) -#define RecEngCon_IsVisible() (g_engdstAddrs.Con_IsVisible()) -#define RecEnghudGetGameDir() (g_engdstAddrs.pfnGetGameDirectory()) -#define RecEngCvar_FindVar(a) (g_engdstAddrs.pfnGetCvarPointer(&a)) -#define RecEngKey_NameForBinding(a) (g_engdstAddrs.Key_LookupBinding(&a)) -#define RecEnghudGetLevelName() (g_engdstAddrs.pfnGetLevelName()) -#define RecEnghudGetScreenFade(a) (g_engdstAddrs.pfnGetScreenFade(&a)) -#define RecEnghudSetScreenFade(a) (g_engdstAddrs.pfnSetScreenFade(&a)) -#define RecEngVGuiWrap_GetPanel() (g_engdstAddrs.VGui_GetPanel()) -#define RecEngVGui_ViewportPaintBackground(a) (g_engdstAddrs.VGui_ViewportPaintBackground(&a)) -#define RecEngCOM_LoadFile(a, b, c) (g_engdstAddrs.COM_LoadFile(&a, &b, &c)) -#define RecEngCOM_ParseFile(a, b) (g_engdstAddrs.COM_ParseFile(&a, &b)) -#define RecEngCOM_FreeFile(a) (g_engdstAddrs.COM_FreeFile(&a)) -#define RecEngCL_IsSpectateOnly() (g_engdstAddrs.IsSpectateOnly()) -#define RecEngR_LoadMapSprite(a) (g_engdstAddrs.LoadMapSprite(&a)) -#define RecEngCOM_AddAppDirectoryToSearchPath(a, b) (g_engdstAddrs.COM_AddAppDirectoryToSearchPath(&a, &b)) -#define RecEngClientDLL_ExpandFileName(a, b, c) (g_engdstAddrs.COM_ExpandFilename(&a, &b, &c)) -#define RecEngPlayerInfo_ValueForKey(a, b) (g_engdstAddrs.PlayerInfo_ValueForKey(&a, &b)) -#define RecEngPlayerInfo_SetValueForKey(a, b) (g_engdstAddrs.PlayerInfo_SetValueForKey(&a, &b)) -#define RecEngGetPlayerUniqueID(a, b) (g_engdstAddrs.GetPlayerUniqueID(&a, &b)) -#define RecEngGetTrackerIDForPlayer(a) (g_engdstAddrs.GetTrackerIDForPlayer(&a)) -#define RecEngGetPlayerForTrackerID(a) (g_engdstAddrs.GetPlayerForTrackerID(&a)) -#define RecEnghudServerCmdUnreliable(a) (g_engdstAddrs.pfnServerCmdUnreliable(&a)) -#define RecEngGetMousePos(a) (g_engdstAddrs.pfnGetMousePos(&a)) -#define RecEngSetMousePos(a, b) (g_engdstAddrs.pfnSetMousePos(&a, &b)) -#define RecEngSetMouseEnable(a) (g_engdstAddrs.pfnSetMouseEnable(&a)) -#define RecEngSetFilterMode(a) (g_engdstAddrs.pfnSetFilterMode(&a)) -#define RecEngSetFilterColor(a,b,c) (g_engdstAddrs.pfnSetFilterColor(&a,&b,&c)) -#define RecEngSetFilterBrightness(a) (g_engdstAddrs.pfnSetFilterBrightness(&a)) -#define RecEngSequenceGet(a,b) (g_engdstAddrs.pfnSequenceGet(&a,&b)) -#define RecEngSPR_DrawGeneric(a,b,c,d,e,f,g,h) (g_engdstAddrs.pfnSPR_DrawGeneric(&a, &b, &c, &d, &e, &f, &g, &h)) -#define RecEngSequencePickSentence(a,b,c) (g_engdstAddrs.pfnSequencePickSentence(&a, &b, &c)) -#define RecEngLocalPlayerInfo_ValueForKey(a) (g_engdstAddrs.LocalPlayerInfo_ValueForKey(&a)) -#define RecEngProcessTutorMessageDecayBuffer(a, b) (g_engdstAddrs.pfnProcessTutorMessageDecayBuffer(&a, &b)) -#define RecEngConstructTutorMessageDecayBuffer(a, b) (g_engdstAddrs.pfnConstructTutorMessageDecayBuffer(&a, &b)) -#define RecEngResetTutorMessageDecayBuffer() (g_engdstAddrs.pfnResetTutorMessageDecayBuffer()) -#define RecEngDraw_FillRGBABlend(a, b, c, d, e, f, g, h) (g_engdstAddrs.pfnFillRGBABlend(&a, &b, &c, &d, &e, &f, &g, &h)) - -// Dummy destination function for use when there's no security module -extern void NullDst(void); - -// Use this to init an engdst structure to point to NullDst -#define k_engdstNull \ -{ \ - (pfnEngDst_pfnSPR_Load_t) NullDst, \ - (pfnEngDst_pfnSPR_Frames_t) NullDst, \ - (pfnEngDst_pfnSPR_Height_t) NullDst, \ - (pfnEngDst_pfnSPR_Width_t) NullDst, \ - (pfnEngDst_pfnSPR_Set_t) NullDst, \ - (pfnEngDst_pfnSPR_Draw_t) NullDst, \ - (pfnEngDst_pfnSPR_DrawHoles_t) NullDst, \ - (pfnEngDst_pfnSPR_DrawAdditive_t) NullDst, \ - (pfnEngDst_pfnSPR_EnableScissor_t) NullDst, \ - (pfnEngDst_pfnSPR_DisableScissor_t) NullDst, \ - (pfnEngDst_pfnSPR_GetList_t) NullDst, \ - (pfnEngDst_pfnFillRGBA_t) NullDst, \ - (pfnEngDst_pfnGetScreenInfo_t) NullDst, \ - (pfnEngDst_pfnSetCrosshair_t) NullDst, \ - (pfnEngDst_pfnRegisterVariable_t) NullDst, \ - (pfnEngDst_pfnGetCvarFloat_t) NullDst, \ - (pfnEngDst_pfnGetCvarString_t) NullDst, \ - (pfnEngDst_pfnAddCommand_t) NullDst, \ - (pfnEngDst_pfnHookUserMsg_t) NullDst, \ - (pfnEngDst_pfnServerCmd_t) NullDst, \ - (pfnEngDst_pfnClientCmd_t) NullDst, \ - (pfnEngDst_pfnGetPlayerInfo_t) NullDst, \ - (pfnEngDst_pfnPlaySoundByName_t) NullDst, \ - (pfnEngDst_pfnPlaySoundByIndex_t) NullDst, \ - (pfnEngDst_pfnAngleVectors_t) NullDst, \ - (pfnEngDst_pfnTextMessageGet_t) NullDst, \ - (pfnEngDst_pfnDrawCharacter_t) NullDst, \ - (pfnEngDst_pfnDrawConsoleString_t) NullDst, \ - (pfnEngDst_pfnDrawSetTextColor_t) NullDst, \ - (pfnEngDst_pfnDrawConsoleStringLen_t) NullDst, \ - (pfnEngDst_pfnConsolePrint_t) NullDst, \ - (pfnEngDst_pfnCenterPrint_t) NullDst, \ - (pfnEngDst_GetWindowCenterX_t) NullDst, \ - (pfnEngDst_GetWindowCenterY_t) NullDst, \ - (pfnEngDst_GetViewAngles_t) NullDst, \ - (pfnEngDst_SetViewAngles_t) NullDst, \ - (pfnEngDst_GetMaxClients_t) NullDst, \ - (pfnEngDst_Cvar_SetValue_t) NullDst, \ - (pfnEngDst_Cmd_Argc_t) NullDst, \ - (pfnEngDst_Cmd_Argv_t) NullDst, \ - (pfnEngDst_Con_Printf_t) NullDst, \ - (pfnEngDst_Con_DPrintf_t) NullDst, \ - (pfnEngDst_Con_NPrintf_t) NullDst, \ - (pfnEngDst_Con_NXPrintf_t) NullDst, \ - (pfnEngDst_PhysInfo_ValueForKey_t) NullDst, \ - (pfnEngDst_ServerInfo_ValueForKey_t) NullDst, \ - (pfnEngDst_GetClientMaxspeed_t) NullDst, \ - (pfnEngDst_CheckParm_t) NullDst, \ - (pfnEngDst_Key_Event_t) NullDst, \ - (pfnEngDst_GetMousePosition_t) NullDst, \ - (pfnEngDst_IsNoClipping_t) NullDst, \ - (pfnEngDst_GetLocalPlayer_t) NullDst, \ - (pfnEngDst_GetViewModel_t) NullDst, \ - (pfnEngDst_GetEntityByIndex_t) NullDst, \ - (pfnEngDst_GetClientTime_t) NullDst, \ - (pfnEngDst_V_CalcShake_t) NullDst, \ - (pfnEngDst_V_ApplyShake_t) NullDst, \ - (pfnEngDst_PM_PointContents_t) NullDst, \ - (pfnEngDst_PM_WaterEntity_t) NullDst, \ - (pfnEngDst_PM_TraceLine_t) NullDst, \ - (pfnEngDst_CL_LoadModel_t) NullDst, \ - (pfnEngDst_CL_CreateVisibleEntity_t) NullDst, \ - (pfnEngDst_GetSpritePointer_t) NullDst, \ - (pfnEngDst_pfnPlaySoundByNameAtLocation_t) NullDst, \ - (pfnEngDst_pfnPrecacheEvent_t) NullDst, \ - (pfnEngDst_pfnPlaybackEvent_t) NullDst, \ - (pfnEngDst_pfnWeaponAnim_t) NullDst, \ - (pfnEngDst_pfnRandomFloat_t) NullDst, \ - (pfnEngDst_pfnRandomLong_t) NullDst, \ - (pfnEngDst_pfnHookEvent_t) NullDst, \ - (pfnEngDst_Con_IsVisible_t) NullDst, \ - (pfnEngDst_pfnGetGameDirectory_t) NullDst, \ - (pfnEngDst_pfnGetCvarPointer_t) NullDst, \ - (pfnEngDst_Key_LookupBinding_t) NullDst, \ - (pfnEngDst_pfnGetLevelName_t) NullDst, \ - (pfnEngDst_pfnGetScreenFade_t) NullDst, \ - (pfnEngDst_pfnSetScreenFade_t) NullDst, \ - (pfnEngDst_VGui_GetPanel_t) NullDst, \ - (pfnEngDst_VGui_ViewportPaintBackground_t) NullDst, \ - (pfnEngDst_COM_LoadFile_t) NullDst, \ - (pfnEngDst_COM_ParseFile_t) NullDst, \ - (pfnEngDst_COM_FreeFile_t) NullDst, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - (pfnEngDst_IsSpectateOnly_t) NullDst, \ - (pfnEngDst_LoadMapSprite_t) NullDst, \ - (pfnEngDst_COM_AddAppDirectoryToSearchPath_t) NullDst, \ - (pfnEngDst_COM_ExpandFilename_t) NullDst, \ - (pfnEngDst_PlayerInfo_ValueForKey_t) NullDst, \ - (pfnEngDst_PlayerInfo_SetValueForKey_t) NullDst, \ - (pfnEngDst_GetPlayerUniqueID_t) NullDst, \ - (pfnEngDst_GetTrackerIDForPlayer_t) NullDst, \ - (pfnEngDst_GetPlayerForTrackerID_t) NullDst, \ - (pfnEngDst_pfnServerCmdUnreliable_t) NullDst, \ - (pfnEngDst_GetMousePos_t) NullDst, \ - (pfnEngDst_SetMousePos_t) NullDst, \ - (pfnEngDst_SetMouseEnable_t) NullDst, \ - (pfnEngDst_pfnSetFilterMode_t) NullDst, \ - (pfnEngDst_pfnSetFilterColor_t) NullDst, \ - (pfnEngDst_pfnSetFilterBrightness_t) NullDst, \ - (pfnEngDst_pfnSequenceGet_t) NullDst, \ - (pfnEngDst_pfnSPR_DrawGeneric_t) NullDst, \ - (pfnEngDst_pfnSequencePickSentence_t) NullDst, \ - (pfnEngDst_pfnDrawString_t) NullDst, \ - (pfnEngDst_pfnDrawStringReverse_t) NullDst, \ - (pfnEngDst_LocalPlayerInfo_ValueForKey_t) NullDst, \ - (pfnEngDst_pfnVGUI2DrawCharacter_t) NullDst, \ - (pfnEngDst_pfnVGUI2DrawCharacterAdd_t) NullDst, \ - (pfnEngDst_pfnPlaySoundVoiceByName_t) NullDst, \ - (pfnEngDst_pfnPrimeMusicStream_t) NullDst, \ - (pfnEngDst_pfnProcessTutorMessageDecayBuffer_t) NullDst, \ - (pfnEngDst_pfnConstructTutorMessageDecayBuffer_t) NullDst, \ - (pfnEngDst_pfnResetTutorMessageDecayData_t) NullDst, \ - (pfnEngDst_pfnPlaySoundByNameAtPitch_t) NullDst, \ - (pfnEngDst_pfnFillRGBABlend_t) NullDst, \ - (pfnEngDst_pfnGetAppID_t) NullDst, \ - (pfnEngDst_pfnGetAliases_t) NullDst, \ - (pfnEngDst_pfnVguiWrap2_GetMouseDelta_t) NullDst, \ -}; - -// Use this to init a cldll_func_dst structure to point to NullDst -#define k_cldstNull \ -{ \ - (DST_INITIALIZE_FUNC) NullDst, \ - (DST_HUD_INIT_FUNC) NullDst, \ - (DST_HUD_VIDINIT_FUNC) NullDst, \ - (DST_HUD_REDRAW_FUNC) NullDst, \ - (DST_HUD_UPDATECLIENTDATA_FUNC) NullDst, \ - (DST_HUD_RESET_FUNC) NullDst, \ - (DST_HUD_CLIENTMOVE_FUNC) NullDst, \ - (DST_HUD_CLIENTMOVEINIT_FUNC) NullDst, \ - (DST_HUD_TEXTURETYPE_FUNC) NullDst, \ - (DST_HUD_IN_ACTIVATEMOUSE_FUNC) NullDst, \ - (DST_HUD_IN_DEACTIVATEMOUSE_FUNC) NullDst, \ - (DST_HUD_IN_MOUSEEVENT_FUNC) NullDst, \ - (DST_HUD_IN_CLEARSTATES_FUNC) NullDst, \ - (DST_HUD_IN_ACCUMULATE_FUNC) NullDst, \ - (DST_HUD_CL_CREATEMOVE_FUNC) NullDst, \ - (DST_HUD_CL_ISTHIRDPERSON_FUNC) NullDst, \ - (DST_HUD_CL_GETCAMERAOFFSETS_FUNC) NullDst, \ - (DST_HUD_KB_FIND_FUNC) NullDst, \ - (DST_HUD_CAMTHINK_FUNC) NullDst, \ - (DST_HUD_CALCREF_FUNC) NullDst, \ - (DST_HUD_ADDENTITY_FUNC) NullDst, \ - (DST_HUD_CREATEENTITIES_FUNC) NullDst, \ - (DST_HUD_DRAWNORMALTRIS_FUNC) NullDst, \ - (DST_HUD_DRAWTRANSTRIS_FUNC) NullDst, \ - (DST_HUD_STUDIOEVENT_FUNC) NullDst, \ - (DST_HUD_POSTRUNCMD_FUNC) NullDst, \ - (DST_HUD_SHUTDOWN_FUNC) NullDst, \ - (DST_HUD_TXFERLOCALOVERRIDES_FUNC) NullDst, \ - (DST_HUD_PROCESSPLAYERSTATE_FUNC) NullDst, \ - (DST_HUD_TXFERPREDICTIONDATA_FUNC) NullDst, \ - (DST_HUD_DEMOREAD_FUNC) NullDst, \ - (DST_HUD_CONNECTIONLESS_FUNC) NullDst, \ - (DST_HUD_GETHULLBOUNDS_FUNC) NullDst, \ - (DST_HUD_FRAME_FUNC) NullDst, \ - (DST_HUD_KEY_EVENT_FUNC) NullDst, \ - (DST_HUD_TEMPENTUPDATE_FUNC) NullDst, \ - (DST_HUD_GETUSERENTITY_FUNC) NullDst, \ - (DST_HUD_VOICESTATUS_FUNC) NullDst, \ - (DST_HUD_DIRECTORMESSAGE_FUNC) NullDst, \ - (DST_HUD_STUDIO_INTERFACE_FUNC) NullDst, \ - (DST_HUD_CHATINPUTPOSITION_FUNC) NullDst, \ - (DST_HUD_GETPLAYERTEAM) NullDst, \ -} - -#ifdef __cplusplus -} -#endif - -#endif // CDLL_INT_H - \ No newline at end of file diff --git a/sdk/pm_shared/pm_debug.c b/sdk/pm_shared/pm_debug.c deleted file mode 100644 index 3b0879c..0000000 --- a/sdk/pm_shared/pm_debug.c +++ /dev/null @@ -1,322 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "mathlib.h" -#include "const.h" -#include "usercmd.h" -#include "pm_defs.h" -#include "pm_shared.h" -#include "pm_movevars.h" -#include "pm_debug.h" - -#include - -#ifdef _MSC_VER -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) -#endif - -extern playermove_t *pmove; - -// Expand debugging BBOX particle hulls by this many units. -#define BOX_GAP 0.0f - -static int PM_boxpnt[6][4] = -{ - { 0, 4, 6, 2 }, // +X - { 0, 1, 5, 4 }, // +Y - { 0, 2, 3, 1 }, // +Z - { 7, 5, 1, 3 }, // -X - { 7, 3, 2, 6 }, // -Y - { 7, 6, 4, 5 }, // -Z -}; - -void PM_ShowClipBox( void ) -{ -#if defined( _DEBUG ) - vec3_t org; - vec3_t offset = { 0, 0, 0 }; - - if ( !pmove->runfuncs ) - return; - - // More debugging, draw the particle bbox for player and for the entity we are looking directly at. - // aslo prints entity info to the console overlay. - //if ( !pmove->server ) - // return; - - // Draw entity in center of view - // Also draws the normal to the clip plane that intersects our movement ray. Leaves a particle - // trail at the intersection point. - PM_ViewEntity(); - - VectorCopy( pmove->origin, org ); - - if ( pmove->server ) - { - VectorAdd( org, offset, org ); - } - else - { - VectorSubtract( org, offset, org ); - } - - // Show our BBOX in particles. - PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], org, pmove->server ? 132 : 0, 0.1 ); - - PM_ParticleLine( org, org, pmove->server ? 132 : 0, 0.1, 5.0 ); -/* - { - int i; - for ( i = 0; i < pmove->numphysent; i++ ) - { - if ( pmove->physents[ i ].info >= 1 && pmove->physents[ i ].info <= 4 ) - { - PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], pmove->physents[i].origin, 132, 0.1 ); - } - } - } -*/ -#endif -} - -/* -=============== -PM_ParticleLine(vec3_t start, vec3_t end, int color, float life) - -================ -*/ -void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert) -{ - float linestep = 2.0f; - float curdist; - float len; - vec3_t curpos; - vec3_t diff; - int i; - // Determine distance; - - VectorSubtract(end, start, diff); - - len = VectorNormalize(diff); - - curdist = 0; - while (curdist <= len) - { - for (i = 0; i < 3; i++) - curpos[i] = start[i] + curdist * diff[i]; - - pmove->PM_Particle( curpos, pcolor, life, 0, vert); - curdist += linestep; - } - -} - -/* -================ -PM_DrawRectangle(vec3_t tl, vec3_t br) - -================ -*/ -void PM_DrawRectangle(vec3_t tl, vec3_t bl, vec3_t tr, vec3_t br, int pcolor, float life) -{ - PM_ParticleLine(tl, bl, pcolor, life, 0); - PM_ParticleLine(bl, br, pcolor, life, 0); - PM_ParticleLine(br, tr, pcolor, life, 0); - PM_ParticleLine(tr, tl, pcolor, life, 0); -} - -/* -================ -PM_DrawPhysEntBBox(int num) - -================ -*/ -void PM_DrawPhysEntBBox(int num, int pcolor, float life) -{ - physent_t *pe; - vec3_t org; - int j; - vec3_t tmp; - vec3_t p[8]; - float gap = BOX_GAP; - vec3_t modelmins, modelmaxs; - - if (num >= pmove->numphysent || - num <= 0) - return; - - pe = &pmove->physents[num]; - - if (pe->model) - { - VectorCopy(pe->origin, org); - - pmove->PM_GetModelBounds( pe->model, modelmins, modelmaxs ); - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? modelmins[0] - gap : modelmaxs[0] + gap; - tmp[1] = (j & 2) ? modelmins[1] - gap : modelmaxs[1] + gap; - tmp[2] = (j & 4) ? modelmins[2] - gap : modelmaxs[2] + gap; - - VectorCopy(tmp, p[j]); - } - - // If the bbox should be rotated, do that - if (pe->angles[0] || pe->angles[1] || pe->angles[2]) - { - vec3_t forward, right, up; - - AngleVectorsTranspose(pe->angles, forward, right, up); - for (j = 0; j < 8; j++) - { - VectorCopy(p[j], tmp); - p[j][0] = DotProduct ( tmp, forward ); - p[j][1] = DotProduct ( tmp, right ); - p[j][2] = DotProduct ( tmp, up ); - } - } - - // Offset by entity origin, if any. - for (j = 0; j < 8; j++) - VectorAdd(p[j], org, p[j]); - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } - } - else - { - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? pe->mins[0] : pe->maxs[0]; - tmp[1] = (j & 2) ? pe->mins[1] : pe->maxs[1]; - tmp[2] = (j & 4) ? pe->mins[2] : pe->maxs[2]; - - VectorAdd(tmp, pe->origin, tmp); - VectorCopy(tmp, p[j]); - } - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } - - } -} - -/* -================ -PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) - -================ -*/ -void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) -{ - int j; - - vec3_t tmp; - vec3_t p[8]; - float gap = BOX_GAP; - - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? mins[0] - gap : maxs[0] + gap; - tmp[1] = (j & 2) ? mins[1] - gap : maxs[1] + gap ; - tmp[2] = (j & 4) ? mins[2] - gap : maxs[2] + gap ; - - VectorAdd(tmp, origin, tmp); - VectorCopy(tmp, p[j]); - } - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } -} - - -#ifndef DEDICATED - -/* -================ -PM_ViewEntity - -Shows a particle trail from player to entity in crosshair. -Shows particles at that entities bbox - -Tries to shoot a ray out by about 128 units. -================ -*/ -void PM_ViewEntity( void ) -{ - vec3_t forward, right, up; - float raydist = 256.0f; - vec3_t origin; - vec3_t end; - int i; - pmtrace_t trace; - int pcolor = 77; - float fup; - -#if 0 - if ( !pm_showclip.value ) - return; -#endif - - AngleVectors (pmove->angles, forward, right, up); // Determine movement angles - - VectorCopy( pmove->origin, origin); - - fup = 0.5*( pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2] ); - fup += pmove->view_ofs[2]; - fup -= 4; - - for (i = 0; i < 3; i++) - { - end[i] = origin[i] + raydist * forward[i]; - } - - trace = pmove->PM_PlayerTrace( origin, end, PM_STUDIO_BOX, -1 ); - - if (trace.ent > 0) // Not the world - { - pcolor = 111; - } - - // Draw the hull or bbox. - if (trace.ent > 0) - { - PM_DrawPhysEntBBox(trace.ent, pcolor, 0.3f); - } -} - -#endif diff --git a/sdk/pm_shared/pm_debug.h b/sdk/pm_shared/pm_debug.h deleted file mode 100644 index a506d37..0000000 --- a/sdk/pm_shared/pm_debug.h +++ /dev/null @@ -1,28 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#ifndef PM_DEBUG_H -#define PM_DEBUG_H -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -void PM_ViewEntity( void ); -void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life); -void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert); -void PM_ShowClipBox( void ); - -#endif // PMOVEDBG_H diff --git a/sdk/pm_shared/pm_defs.h b/sdk/pm_shared/pm_defs.h deleted file mode 100644 index f4e4d6d..0000000 --- a/sdk/pm_shared/pm_defs.h +++ /dev/null @@ -1,267 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// pm_defs.h -#if !defined( PM_DEFSH ) -#define PM_DEFSH -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#include "archtypes.h" // DAL -#define MAX_PHYSENTS 600 // Must have room for all entities in the world. -#define MAX_MOVEENTS 64 -#define MAX_CLIP_PLANES 5 - -#define PM_NORMAL 0x00000000 -#define PM_STUDIO_IGNORE 0x00000001 // Skip studio models -#define PM_STUDIO_BOX 0x00000002 // Use boxes for non-complex studio models (even in traceline) -#define PM_GLASS_IGNORE 0x00000004 // Ignore entities with non-normal rendermode -#define PM_WORLD_ONLY 0x00000008 // Only trace against the world - -// Values for flags parameter of PM_TraceLine -#define PM_TRACELINE_PHYSENTSONLY 0 -#define PM_TRACELINE_ANYVISIBLE 1 - -#if defined _MSC_VER && _MSC_VER >= 1400 - #ifndef _CRT_SECURE_NO_DEPRECATE - #define _CRT_SECURE_NO_DEPRECATE - #endif - - #pragma warning(disable: 4996) // deprecated functions -#endif - -#include "pm_info.h" - -// PM_PlayerTrace results. -#include "pmtrace.h" - -#if !defined ( USERCMD_H ) -#include "usercmd.h" -#endif - -// physent_t -typedef struct physent_s -{ - char name[32]; // Name of model, or "player" or "world". - int player; - vec3_t origin; // Model's origin in world coordinates. - struct model_s *model; // only for bsp models - struct model_s *studiomodel; // SOLID_BBOX, but studio clip intersections. - vec3_t mins, maxs; // only for non-bsp models - int info; // For client or server to use to identify (index into edicts or cl_entities) - vec3_t angles; // rotated entities need this info for hull testing to work. - - int solid; // Triggers and func_door type WATER brushes are SOLID_NOT - int skin; // BSP Contents for such things like fun_door water brushes. - int rendermode; // So we can ignore glass - - // Complex collision detection. - float frame; - int sequence; - byte controller[4]; - byte blending[2]; - - int movetype; - int takedamage; - int blooddecal; - int team; - int classnumber; - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; -} physent_t; - -#ifndef _DCLIPNODE_DEFINED_ -#define _DCLIPNODE_DEFINED_ -typedef struct -{ - int planenum; - short children[2]; // negative numbers are contents -} dclipnode_t; -#endif - -#ifndef _MPLANE_DEFINED_ -#define _MPLANE_DEFINED_ -typedef struct mplane_s -{ - vec3_t normal; // surface normal - float dist; // closest appoach to origin - byte type; // for texture axis selection and fast side tests - byte signbits; // signx + signy<<1 + signz<<1 - byte pad[2]; -} mplane_t; -#endif - -#ifndef _HULL_DEFINED_ -#define _HULL_DEFINED_ -typedef struct hull_s -{ - dclipnode_t *clipnodes; - mplane_t *planes; - int firstclipnode; - int lastclipnode; - vec3_t clip_mins; - vec3_t clip_maxs; -} hull_t; -#endif - -typedef struct playermove_s -{ - int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. - qboolean server; // For debugging, are we running physics code on server side? - - qboolean multiplayer; // 1 == multiplayer server - float time; // realtime on host, for reckoning duck timing - float frametime; // Duration of this frame - - vec3_t forward, right, up; // Vectors for angles - // player state - vec3_t origin; // Movement origin. - vec3_t angles; // Movement view angles. - vec3_t oldangles; // Angles before movement view angles were looked at. - vec3_t velocity; // Current movement direction. - vec3_t movedir; // For waterjumping, a forced forward velocity so we can fly over lip of ledge. - vec3_t basevelocity; // Velocity of the conveyor we are standing, e.g. - - // For ducking/dead - vec3_t view_ofs; // Our eye position. - float flDuckTime; // Time we started duck - qboolean bInDuck; // In process of ducking or ducked already? - - // For walking/falling - int flTimeStepSound; // Next time we can play a step sound - int iStepLeft; - - float flFallVelocity; - vec3_t punchangle; - - float flSwimTime; - - float flNextPrimaryAttack; - - int effects; // MUZZLE FLASH, e.g. - - int flags; // FL_ONGROUND, FL_DUCKING, etc. - int usehull; // 0 = regular player hull, 1 = ducked player hull, 2 = point hull - float gravity; // Our current gravity and friction. - float friction; - int oldbuttons; // Buttons last usercmd - float waterjumptime; // Amount of time left in jumping out of water cycle. - qboolean dead; // Are we a dead player? - int deadflag; - int spectator; // Should we use spectator physics model? - int movetype; // Our movement type, NOCLIP, WALK, FLY - - int onground; - int waterlevel; - int watertype; - int oldwaterlevel; - - char sztexturename[256]; - char chtexturetype; - - float maxspeed; - float clientmaxspeed; // Player specific maxspeed - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; - // world state - // Number of entities to clip against. - int numphysent; - physent_t physents[MAX_PHYSENTS]; - // Number of momvement entities (ladders) - int nummoveent; - // just a list of ladders - physent_t moveents[MAX_MOVEENTS]; - - // All things being rendered, for tracing against things you don't actually collide with - int numvisent; - physent_t visents[ MAX_PHYSENTS ]; - - // input to run through physics. - usercmd_t cmd; - - // Trace results for objects we collided with. - int numtouch; - pmtrace_t touchindex[MAX_PHYSENTS]; - - char physinfo[ MAX_PHYSINFO_STRING ]; // Physics info string - - struct movevars_s *movevars; - vec3_t player_mins[ 4 ]; - vec3_t player_maxs[ 4 ]; - - // Common functions - const char *(*PM_Info_ValueForKey) ( const char *s, const char *key ); - void (*PM_Particle)( float *origin, int color, float life, int zpos, int zvel); - int (*PM_TestPlayerPosition) (float *pos, pmtrace_t *ptrace ); - void (*Con_NPrintf)( int idx, char *fmt, ... ); - void (*Con_DPrintf)( char *fmt, ... ); - void (*Con_Printf)( char *fmt, ... ); - double (*Sys_FloatTime)( void ); - void (*PM_StuckTouch)( int hitent, pmtrace_t *ptraceresult ); - int (*PM_PointContents) (float *p, int *truecontents /*filled in if this is non-null*/ ); - int (*PM_TruePointContents) (float *p); - int (*PM_HullPointContents) ( struct hull_s *hull, int num, float *p); - pmtrace_t (*PM_PlayerTrace) (float *start, float *end, int traceFlags, int ignore_pe ); - struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); - int32 (*RandomLong)( int32 lLow, int32 lHigh ); - float (*RandomFloat)( float flLow, float flHigh ); - int (*PM_GetModelType)( struct model_s *mod ); - void (*PM_GetModelBounds)( struct model_s *mod, float *mins, float *maxs ); - void *(*PM_HullForBsp)( physent_t *pe, float *offset ); - float (*PM_TraceModel)( physent_t *pEnt, float *start, float *end, trace_t *trace ); - int (*COM_FileSize)(char *filename); - byte *(*COM_LoadFile) (char *path, int usehunk, int *pLength); - void (*COM_FreeFile) ( void *buffer ); - char *(*memfgets)( byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize ); - - // Functions - // Run functions for this frame? - qboolean runfuncs; - void (*PM_PlaySound) ( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); - const char *(*PM_TraceTexture) ( int ground, float *vstart, float *vend ); - void (*PM_PlaybackEventFull) ( int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); - - pmtrace_t (*PM_PlayerTraceEx) (float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ) ); - int (*PM_TestPlayerPositionEx) (float *pos, pmtrace_t *ptrace, int (*pfnIgnore)( physent_t *pe ) ); - struct pmtrace_s *(*PM_TraceLineEx)( float *start, float *end, int flags, int usehulll, int (*pfnIgnore)( physent_t *pe ) ); -} playermove_t; - -#endif diff --git a/sdk/pm_shared/pm_info.h b/sdk/pm_shared/pm_info.h deleted file mode 100644 index fa3cc19..0000000 --- a/sdk/pm_shared/pm_info.h +++ /dev/null @@ -1,26 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// Physics info string definition -#if !defined( PM_INFOH ) -#define PM_INFOH -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#define MAX_PHYSINFO_STRING 256 - -#endif // PM_INFOH diff --git a/sdk/pm_shared/pm_materials.h b/sdk/pm_shared/pm_materials.h deleted file mode 100644 index a20edd8..0000000 --- a/sdk/pm_shared/pm_materials.h +++ /dev/null @@ -1,38 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -#if !defined( PM_MATERIALSH ) -#define PM_MATERIALSH -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -#define CBTEXTURENAMEMAX 13 // only load first n chars of name - -#define CHAR_TEX_CONCRETE 'C' // texture types -#define CHAR_TEX_METAL 'M' -#define CHAR_TEX_DIRT 'D' -#define CHAR_TEX_VENT 'V' -#define CHAR_TEX_GRATE 'G' -#define CHAR_TEX_TILE 'T' -#define CHAR_TEX_SLOSH 'S' -#define CHAR_TEX_WOOD 'W' -#define CHAR_TEX_COMPUTER 'P' -#define CHAR_TEX_GLASS 'Y' -#define CHAR_TEX_FLESH 'F' -#define CHAR_TEX_SNOW 'N' - -#endif // !PM_MATERIALSH diff --git a/sdk/pm_shared/pm_math.c b/sdk/pm_shared/pm_math.c deleted file mode 100644 index 3cb84e2..0000000 --- a/sdk/pm_shared/pm_math.c +++ /dev/null @@ -1,435 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// pm_math.c -- math primitives - -#include "mathlib.h" -#include "const.h" -#include - -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - -#ifdef _MSC_VER -#pragma warning(disable : 4244) -#endif - -#ifndef DISABLE_VEC_ORIGIN -vec3_t vec3_origin = {0,0,0}; -#endif -int nanmask = 255<<23; - -float anglemod(float a) -{ - a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535); - return a; -} - -void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - if (forward) - { - forward[0] = cp*cy; - forward[1] = cp*sy; - forward[2] = -sp; - } - if (right) - { - right[0] = (-1*sr*sp*cy+-1*cr*-sy); - right[1] = (-1*sr*sp*sy+-1*cr*cy); - right[2] = -1*sr*cp; - } - if (up) - { - up[0] = (cr*sp*cy+-sr*-sy); - up[1] = (cr*sp*sy+-sr*cy); - up[2] = cr*cp; - } -} - -void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - if (forward) - { - forward[0] = cp*cy; - forward[1] = (sr*sp*cy+cr*-sy); - forward[2] = (cr*sp*cy+-sr*-sy); - } - if (right) - { - right[0] = cp*sy; - right[1] = (sr*sp*sy+cr*cy); - right[2] = (cr*sp*sy+-sr*cy); - } - if (up) - { - up[0] = -sp; - up[1] = sr*cp; - up[2] = cr*cp; - } -} - -#ifndef DISABLE_VEC_FUNCS -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; - matrix[2][0] = -sp; - matrix[0][1] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[2][1] = sr*cp; - matrix[0][2] = (cr*sp*cy+-sr*-sy); - matrix[1][2] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -void AngleIMatrix (const vec3_t angles, float matrix[3][4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[0][1] = cp*sy; - matrix[0][2] = -sp; - matrix[1][0] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[1][2] = sr*cp; - matrix[2][0] = (cr*sp*cy+-sr*-sy); - matrix[2][1] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} -#endif - -void NormalizeAngles( float *angles ) -{ - int i; - // Normalize angles - for ( i = 0; i < 3; i++ ) - { - if ( angles[i] > 180.0 ) - { - angles[i] -= 360.0; - } - else if ( angles[i] < -180.0 ) - { - angles[i] += 360.0; - } - } -} - -/* -=================== -InterpolateAngles - -Interpolate Euler angles. -FIXME: Use Quaternions to avoid discontinuities -Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) -=================== -*/ -void InterpolateAngles( float *start, float *end, float *output, float frac ) -{ - int i; - float ang1, ang2; - float d; - - NormalizeAngles( start ); - NormalizeAngles( end ); - - for ( i = 0 ; i < 3 ; i++ ) - { - ang1 = start[i]; - ang2 = end[i]; - - d = ang2 - ang1; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - output[i] = ang1 + d * frac; - } - - NormalizeAngles( output ); -} - - -/* -=================== -AngleBetweenVectors - -=================== -*/ -float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ) -{ - float angle; - float l1 = Length( v1 ); - float l2 = Length( v2 ); - - if ( !l1 || !l2 ) - return 0.0f; - - angle = acos( DotProduct( v1, v2 ) ) / (l1*l2); - angle = ( angle * 180.0f ) / M_PI; - - return angle; -} - -#ifndef DISABLE_VEC_FUNCS -void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out) -{ - out[0] = DotProduct(in1, in2[0]) + in2[0][3]; - out[1] = DotProduct(in1, in2[1]) + in2[1][3]; - out[2] = DotProduct(in1, in2[2]) + in2[2][3]; -} - -int VectorCompare (const vec3_t v1, const vec3_t v2) -{ - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) - return 0; - - return 1; -} - -void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) -{ - vecc[0] = veca[0] + scale*vecb[0]; - vecc[1] = veca[1] + scale*vecb[1]; - vecc[2] = veca[2] + scale*vecb[2]; -} -#endif - - -vec_t _DotProduct (vec3_t v1, vec3_t v2) -{ - return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; -} - -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) -{ - out[0] = veca[0]-vecb[0]; - out[1] = veca[1]-vecb[1]; - out[2] = veca[2]-vecb[2]; -} - -void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) -{ - out[0] = veca[0]+vecb[0]; - out[1] = veca[1]+vecb[1]; - out[2] = veca[2]+vecb[2]; -} - -void _VectorCopy (vec3_t in, vec3_t out) -{ - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; -} - -#ifndef DISABLE_VEC_FUNCS -void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross) -{ - cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; - cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; - cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} -#endif - -double sqrt(double x); - -#ifndef DISABLE_VEC_FUNCS -float Length(const vec3_t v) -{ - int i; - float length = 0.0f; - - for (i=0 ; i< 3 ; i++) - length += v[i]*v[i]; - length = sqrt (length); // FIXME - - return length; -} -#endif - -float Distance(const vec3_t v1, const vec3_t v2) -{ - vec3_t d; - VectorSubtract(v2,v1,d); - return Length(d); -} - -#ifndef DISABLE_VEC_FUNCS -float VectorNormalize (vec3_t v) -{ - float length, ilength; - - length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); // FIXME - - if (length) - { - ilength = 1/length; - v[0] *= ilength; - v[1] *= ilength; - v[2] *= ilength; - } - - return length; - -} - -void VectorInverse (vec3_t v) -{ - v[0] = -v[0]; - v[1] = -v[1]; - v[2] = -v[2]; -} - -void VectorScale (const vec3_t in, vec_t scale, vec3_t out) -{ - out[0] = in[0]*scale; - out[1] = in[1]*scale; - out[2] = in[2]*scale; -} -#endif - - -int Q_log2(int val) -{ - int answer=0; - while (val>>=1) - answer++; - return answer; -} - -void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up) -{ - vec3_t tmp; - - if (forward[0] == 0 && forward[1] == 0) - { - right[0] = 1; - right[1] = 0; - right[2] = 0; - up[0] = -forward[2]; - up[1] = 0; - up[2] = 0; - return; - } - - tmp[0] = 0; tmp[1] = 0; tmp[2] = 1.0; - CrossProduct( forward, tmp, right ); - VectorNormalize( right ); - CrossProduct( right, forward, up ); - VectorNormalize( up ); -} - - -#ifndef DISABLE_VEC_FUNCS -void VectorAngles( const vec3_t forward, vec3_t angles ) -{ - float tmp, yaw, pitch; - - if (forward[1] == 0 && forward[0] == 0) - { - yaw = 0; - if (forward[2] > 0) - pitch = 90; - else - pitch = 270; - } - else - { - yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); - pitch = (atan2(forward[2], tmp) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - angles[0] = pitch; - angles[1] = yaw; - angles[2] = 0; -} -#endif diff --git a/sdk/pm_shared/pm_movevars.h b/sdk/pm_shared/pm_movevars.h deleted file mode 100644 index 66c99ee..0000000 --- a/sdk/pm_shared/pm_movevars.h +++ /dev/null @@ -1,47 +0,0 @@ -//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -// pm_movevars.h -#if !defined( PM_MOVEVARSH ) -#define PM_MOVEVARSH - -// movevars_t // Physics variables. -typedef struct movevars_s movevars_t; - -struct movevars_s -{ - float gravity; // Gravity for map - float stopspeed; // Deceleration when not moving - float maxspeed; // Max allowed speed - float spectatormaxspeed; - float accelerate; // Acceleration factor - float airaccelerate; // Same for when in open air - float wateraccelerate; // Same for when in water - float friction; - float edgefriction; // Extra friction near dropofs - float waterfriction; // Less in water - float entgravity; // 1.0 - float bounce; // Wall bounce value. 1.0 - float stepsize; // sv_stepsize; - float maxvelocity; // maximum server velocity. - float zmax; // Max z-buffer range (for GL) - float waveHeight; // Water wave height (for GL) - qboolean footsteps; // Play footstep sounds - char skyName[32]; // Name of the sky map - float rollangle; - float rollspeed; - float skycolor_r; // Sky color - float skycolor_g; // - float skycolor_b; // - float skyvec_x; // Sky vector - float skyvec_y; // - float skyvec_z; // -}; - -extern movevars_t movevars; - -#endif diff --git a/sdk/pm_shared/pm_shared.c b/sdk/pm_shared/pm_shared.c deleted file mode 100644 index 2eed093..0000000 --- a/sdk/pm_shared/pm_shared.c +++ /dev/null @@ -1,3343 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include -#include "mathlib.h" -#include "const.h" -#include "usercmd.h" -#include "pm_defs.h" -#include "pm_shared.h" -#include "pm_movevars.h" -#include "pm_debug.h" -#include // NULL -#include // sqrt -#include // strcpy -#include // atoi -#include // isspace - -#ifdef CLIENT_DLL - // Spectator Mode - int iJumpSpectator; -#ifndef DISABLE_JUMP_ORIGIN - float vJumpOrigin[3]; - float vJumpAngles[3]; -#else - extern float vJumpOrigin[3]; - extern float vJumpAngles[3]; -#endif -#endif - -static int pm_shared_initialized = 0; - -#ifdef _MSC_VER -#pragma warning( disable : 4305 ) -#endif - -typedef enum {mod_brush, mod_sprite, mod_alias, mod_studio} modtype_t; - -playermove_t *pmove = NULL; - -// Ducking time -#define TIME_TO_DUCK 0.4 -#define VEC_DUCK_HULL_MIN -18 -#define VEC_DUCK_HULL_MAX 18 -#define VEC_DUCK_VIEW 12 -#define PM_DEAD_VIEWHEIGHT -8 -#define MAX_CLIMB_SPEED 200 -#define STUCK_MOVEUP 1 -#define STUCK_MOVEDOWN -1 -#define VEC_HULL_MIN -36 -#define VEC_HULL_MAX 36 -#define VEC_VIEW 28 -#define STOP_EPSILON 0.1 - -#define CTEXTURESMAX 512 // max number of textures loaded -#define CBTEXTURENAMEMAX 13 // only load first n chars of name - -#define CHAR_TEX_CONCRETE 'C' // texture types -#define CHAR_TEX_METAL 'M' -#define CHAR_TEX_DIRT 'D' -#define CHAR_TEX_VENT 'V' -#define CHAR_TEX_GRATE 'G' -#define CHAR_TEX_TILE 'T' -#define CHAR_TEX_SLOSH 'S' -#define CHAR_TEX_WOOD 'W' -#define CHAR_TEX_COMPUTER 'P' -#define CHAR_TEX_GLASS 'Y' -#define CHAR_TEX_FLESH 'F' - -#define STEP_CONCRETE 0 // default step sound -#define STEP_METAL 1 // metal floor -#define STEP_DIRT 2 // dirt, sand, rock -#define STEP_VENT 3 // ventillation duct -#define STEP_GRATE 4 // metal grating -#define STEP_TILE 5 // floor tiles -#define STEP_SLOSH 6 // shallow liquid puddle -#define STEP_WADE 7 // wading in liquid -#define STEP_LADDER 8 // climbing ladder - -#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump - -#define PLAYER_DUCKING_MULTIPLIER 0.333 - -// double to float warning -#ifdef _MSC_VER -#pragma warning(disable : 4244) -#endif - -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#define min(a, b) (((a) < (b)) ? (a) : (b)) -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - -#define MAX_CLIENTS 32 - -#define CONTENTS_CURRENT_0 -9 -#define CONTENTS_CURRENT_90 -10 -#define CONTENTS_CURRENT_180 -11 -#define CONTENTS_CURRENT_270 -12 -#define CONTENTS_CURRENT_UP -13 -#define CONTENTS_CURRENT_DOWN -14 - -#define CONTENTS_TRANSLUCENT -15 - -static vec3_t rgv3tStuckTable[54]; -static int rgStuckLast[MAX_CLIENTS][2]; - -// Texture names -static int gcTextures = 0; -static char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; -static char grgchTextureType[CTEXTURESMAX]; - -int g_onladder = 0; - -void PM_SwapTextures( int i, int j ) -{ - char chTemp; - char szTemp[ CBTEXTURENAMEMAX ]; - - strcpy( szTemp, grgszTextureName[ i ] ); - chTemp = grgchTextureType[ i ]; - - strcpy( grgszTextureName[ i ], grgszTextureName[ j ] ); - grgchTextureType[ i ] = grgchTextureType[ j ]; - - strcpy( grgszTextureName[ j ], szTemp ); - grgchTextureType[ j ] = chTemp; -} - -void PM_SortTextures( void ) -{ - // Bubble sort, yuck, but this only occurs at startup and it's only 512 elements... - // - int i, j; - - for ( i = 0 ; i < gcTextures; i++ ) - { - for ( j = i + 1; j < gcTextures; j++ ) - { - if ( stricmp( grgszTextureName[ i ], grgszTextureName[ j ] ) > 0 ) - { - // Swap - // - PM_SwapTextures( i, j ); - } - } - } -} - -void PM_InitTextureTypes() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - static qboolean bTextureTypeInit = false; - - if ( bTextureTypeInit ) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - fileSize = pmove->COM_FileSize( "sound/materials.txt" ); - pMemFile = pmove->COM_LoadFile( "sound/materials.txt", 5, NULL ); - if ( !pMemFile ) - return; - - filePos = 0; - // for each line in the file... - while ( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX) ) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - // Must use engine to free since we are in a .dll - pmove->COM_FreeFile ( pMemFile ); - - PM_SortTextures(); - - bTextureTypeInit = true; -} - -char PM_FindTextureType( char *name ) -{ - int left, right, pivot; - int val; - - assert( pm_shared_initialized ); - - left = 0; - right = gcTextures - 1; - - while ( left <= right ) - { - pivot = ( left + right ) / 2; - - val = strnicmp( name, grgszTextureName[ pivot ], CBTEXTURENAMEMAX-1 ); - if ( val == 0 ) - { - return grgchTextureType[ pivot ]; - } - else if ( val > 0 ) - { - left = pivot + 1; - } - else if ( val < 0 ) - { - right = pivot - 1; - } - } - - return CHAR_TEX_CONCRETE; -} - -void PM_PlayStepSound( int step, float fvol ) -{ - static int iSkipStep = 0; - int irand; - vec3_t hvel; - - pmove->iStepLeft = !pmove->iStepLeft; - - if ( !pmove->runfuncs ) - { - return; - } - - irand = pmove->RandomLong(0,1) + ( pmove->iStepLeft * 2 ); - - // FIXME mp_footsteps needs to be a movevar - if ( pmove->multiplayer && !pmove->movevars->footsteps ) - return; - - VectorCopy( pmove->velocity, hvel ); - hvel[2] = 0.0; - - if ( pmove->multiplayer && ( !g_onladder && Length( hvel ) <= 220 ) ) - return; - - // irand - 0,1 for right foot, 2,3 for left foot - // used to alternate left and right foot - // FIXME, move to player state - - switch (step) - { - default: - case STEP_CONCRETE: - switch (irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_METAL: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_DIRT: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_VENT: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_GRATE: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_TILE: - if ( !pmove->RandomLong(0,4) ) - irand = 4; - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 4: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile5.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_SLOSH: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_WADE: - if ( iSkipStep == 0 ) - { - iSkipStep++; - break; - } - - if ( iSkipStep++ == 3 ) - { - iSkipStep = 0; - } - - switch (irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_LADDER: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - } -} - -int PM_MapTextureTypeStepType(char chTextureType) -{ - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: return STEP_CONCRETE; - case CHAR_TEX_METAL: return STEP_METAL; - case CHAR_TEX_DIRT: return STEP_DIRT; - case CHAR_TEX_VENT: return STEP_VENT; - case CHAR_TEX_GRATE: return STEP_GRATE; - case CHAR_TEX_TILE: return STEP_TILE; - case CHAR_TEX_SLOSH: return STEP_SLOSH; - } -} - -/* -==================== -PM_CatagorizeTextureType - -Determine texture info for the texture we are standing on. -==================== -*/ -void PM_CatagorizeTextureType( void ) -{ - vec3_t start, end; - const char *pTextureName; - - VectorCopy( pmove->origin, start ); - VectorCopy( pmove->origin, end ); - - // Straight down - end[2] -= 64; - - // Fill in default values, just in case. - pmove->sztexturename[0] = '\0'; - pmove->chtexturetype = CHAR_TEX_CONCRETE; - - pTextureName = pmove->PM_TraceTexture( pmove->onground, start, end ); - if ( !pTextureName ) - return; - - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - - strcpy( pmove->sztexturename, pTextureName); - pmove->sztexturename[ CBTEXTURENAMEMAX - 1 ] = 0; - - // get texture type - pmove->chtexturetype = PM_FindTextureType( pmove->sztexturename ); -} - -void PM_UpdateStepSound( void ) -{ - int fWalking; - float fvol; - vec3_t knee; - vec3_t feet; -// vec3_t center; - float height; - float speed; - float velrun; - float velwalk; - float flduck; - int fLadder; - int step; - - if ( pmove->flTimeStepSound > 0 ) - return; - - if ( pmove->flags & FL_FROZEN ) - return; - - PM_CatagorizeTextureType(); - - speed = Length( pmove->velocity ); - - // determine if we are on a ladder - fLadder = ( pmove->movetype == MOVETYPE_FLY );// IsOnLadder(); - - // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!! - if ( ( pmove->flags & FL_DUCKING) || fLadder ) - { - velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow - velrun = 80; // UNDONE: Move walking to server - flduck = 100; - } - else - { - velwalk = 120; - velrun = 210; - flduck = 0; - } - - // If we're on a ladder or on the ground, and we're moving fast enough, - // play step sound. Also, if pmove->flTimeStepSound is zero, get the new - // sound right away - we just started moving in new level. - if ( (fLadder || ( pmove->onground != -1 ) ) && - ( Length( pmove->velocity ) > 0.0 ) && - ( speed >= velwalk || !pmove->flTimeStepSound ) ) - { - fWalking = speed < velrun; - -// VectorCopy( pmove->origin, center ); - VectorCopy( pmove->origin, knee ); - VectorCopy( pmove->origin, feet ); - - height = pmove->player_maxs[ pmove->usehull ][ 2 ] - pmove->player_mins[ pmove->usehull ][ 2 ]; - - knee[2] = pmove->origin[2] - 0.3 * height; - feet[2] = pmove->origin[2] - 0.5 * height; - - // find out what we're stepping in or on... - if (fLadder) - { - step = STEP_LADDER; - fvol = 0.35; - pmove->flTimeStepSound = 350; - } - else if ( pmove->PM_PointContents ( knee, NULL ) == CONTENTS_WATER ) - { - step = STEP_WADE; - fvol = 0.65; - pmove->flTimeStepSound = 600; - } - else if ( pmove->PM_PointContents ( feet, NULL ) == CONTENTS_WATER ) - { - step = STEP_SLOSH; - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - } - else - { - // find texture under player, if different from current texture, - // get material type - step = PM_MapTextureTypeStepType( pmove->chtexturetype ); - - switch ( pmove->chtexturetype ) - { - default: - case CHAR_TEX_CONCRETE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_METAL: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_DIRT: - fvol = fWalking ? 0.25 : 0.55; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_VENT: - fvol = fWalking ? 0.4 : 0.7; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_GRATE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_TILE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_SLOSH: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - } - } - - pmove->flTimeStepSound += flduck; // slower step time if ducking - - // play the sound - // 35% volume if ducking - if ( pmove->flags & FL_DUCKING ) - { - fvol *= 0.35; - } - - PM_PlayStepSound( step, fvol ); - } -} - -/* -================ -PM_AddToTouched - -Add's the trace result to touch list, if contact is not already in list. -================ -*/ -qboolean PM_AddToTouched(pmtrace_t tr, vec3_t impactvelocity) -{ - int i; - - for (i = 0; i < pmove->numtouch; i++) - { - if (pmove->touchindex[i].ent == tr.ent) - break; - } - if (i != pmove->numtouch) // Already in list. - return false; - - VectorCopy( impactvelocity, tr.deltavelocity ); - - if (pmove->numtouch >= MAX_PHYSENTS) - pmove->Con_DPrintf("Too many entities were touched!\n"); - - pmove->touchindex[pmove->numtouch++] = tr; - return true; -} - -/* -================ -PM_CheckVelocity - -See if the player has a bogus velocity value. -================ -*/ -void PM_CheckVelocity () -{ - int i; - -// -// bound velocity -// - for (i=0 ; i<3 ; i++) - { - // See if it's bogus. - if (IS_NAN(pmove->velocity[i])) - { - pmove->Con_Printf ("PM Got a NaN velocity %i\n", i); - pmove->velocity[i] = 0; - } - if (IS_NAN(pmove->origin[i])) - { - pmove->Con_Printf ("PM Got a NaN origin on %i\n", i); - pmove->origin[i] = 0; - } - - // Bound it. - if (pmove->velocity[i] > pmove->movevars->maxvelocity) - { - pmove->Con_DPrintf ("PM Got a velocity too high on %i\n", i); - pmove->velocity[i] = pmove->movevars->maxvelocity; - } - else if (pmove->velocity[i] < -pmove->movevars->maxvelocity) - { - pmove->Con_DPrintf ("PM Got a velocity too low on %i\n", i); - pmove->velocity[i] = -pmove->movevars->maxvelocity; - } - } -} - -/* -================== -PM_ClipVelocity - -Slide off of the impacting object -returns the blocked flags: -0x01 == floor -0x02 == step / wall -================== -*/ -int PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) -{ - float backoff; - float change; - float angle; - int i, blocked; - - angle = normal[ 2 ]; - - blocked = 0x00; // Assume unblocked. - if (angle > 0) // If the plane that is blocking us has a positive z component, then assume it's a floor. - blocked |= 0x01; // - if (!angle) // If the plane has no Z, it is vertical (wall/step) - blocked |= 0x02; // - - // Determine how far along plane to slide based on incoming direction. - // Scale by overbounce factor. - backoff = DotProduct (in, normal) * overbounce; - - for (i=0 ; i<3 ; i++) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - // If out velocity is too small, zero it out. - if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) - out[i] = 0; - } - - // Return blocking flags. - return blocked; -} - -void PM_AddCorrectGravity () -{ - float ent_gravity; - - if ( pmove->waterjumptime ) - return; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Add gravity so they'll be in the correct position during movement - // yes, this 0.5 looks wrong, but it's not. - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * 0.5 * pmove->frametime ); - pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; - pmove->basevelocity[2] = 0; - - PM_CheckVelocity(); -} - - -void PM_FixupGravityVelocity () -{ - float ent_gravity; - - if ( pmove->waterjumptime ) - return; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Get the correct velocity for the end of the dt - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime * 0.5 ); - - PM_CheckVelocity(); -} - -/* -============ -PM_FlyMove - -The basic solid body movement clip that slides along multiple planes -============ -*/ -int PM_FlyMove (void) -{ - int bumpcount, numbumps; - vec3_t dir; - float d; - int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; - vec3_t primal_velocity, original_velocity; - vec3_t new_velocity; - int i, j; - pmtrace_t trace; - vec3_t end; - float time_left, allFraction; - int blocked; - - numbumps = 4; // Bump up to four times - - blocked = 0; // Assume not blocked - numplanes = 0; // and not sliding along any planes - VectorCopy (pmove->velocity, original_velocity); // Store original velocity - VectorCopy (pmove->velocity, primal_velocity); - - allFraction = 0; - time_left = pmove->frametime; // Total time for this movement operation. - - for (bumpcount=0 ; bumpcountvelocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) - break; - - // Assume we can move all the way from the current origin to the - // end point. - for (i=0 ; i<3 ; i++) - end[i] = pmove->origin[i] + time_left * pmove->velocity[i]; - - // See if we can make it from origin to end point. - trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); - - allFraction += trace.fraction; - // If we started in a solid object, or we were in solid space - // the whole way, zero out our velocity and return that we - // are blocked by floor and wall. - if (trace.allsolid) - { // entity is trapped in another solid - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf("Trapped 4\n"); - return 4; - } - - // If we moved some portion of the total distance, then - // copy the end position into the pmove->origin and - // zero the plane counter. - if (trace.fraction > 0) - { // actually covered some distance - VectorCopy (trace.endpos, pmove->origin); - VectorCopy (pmove->velocity, original_velocity); - numplanes = 0; - } - - // If we covered the entire distance, we are done - // and can return. - if (trace.fraction == 1) - break; // moved the entire distance - - //if (!trace.ent) - // Sys_Error ("PM_PlayerTrace: !trace.ent"); - - // Save entity that blocked us (since fraction was < 1.0) - // for contact - // Add it if it's not already in the list!!! - PM_AddToTouched(trace, pmove->velocity); - - // If the plane we hit has a high z component in the normal, then - // it's probably a floor - if (trace.plane.normal[2] > 0.7) - { - blocked |= 1; // floor - } - // If the plane has a zero z component in the normal, then it's a - // step or wall - if (!trace.plane.normal[2]) - { - blocked |= 2; // step / wall - //Con_DPrintf("Blocked by %i\n", trace.ent); - } - - // Reduce amount of pmove->frametime left by total time left * fraction - // that we covered. - time_left -= time_left * trace.fraction; - - // Did we run out of planes to clip against? - if (numplanes >= MAX_CLIP_PLANES) - { // this shouldn't really happen - // Stop our movement if so. - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf("Too many planes 4\n"); - - break; - } - - // Set up next clipping plane - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; -// - -// modify original_velocity so it parallels all of the clip planes -// - if ( pmove->movetype == MOVETYPE_WALK && - ((pmove->onground == -1) || (pmove->friction != 1)) ) // relfect player velocity - { - for ( i = 0; i < numplanes; i++ ) - { - if ( planes[i][2] > 0.7 ) - {// floor or slope - PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); - VectorCopy( new_velocity, original_velocity ); - } - else - PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + pmove->movevars->bounce * (1-pmove->friction) ); - } - - VectorCopy( new_velocity, pmove->velocity ); - VectorCopy( new_velocity, original_velocity ); - } - else - { - for (i=0 ; ivelocity, - 1); - for (j=0 ; jvelocity, planes[j]) < 0) - break; // not ok - } - if (j == numplanes) // Didn't have to clip, so we're ok - break; - } - - // Did we go all the way through plane set - if (i != numplanes) - { // go along this plane - // pmove->velocity is set in clipping call, no need to set again. - ; - } - else - { // go along the crease - if (numplanes != 2) - { - //Con_Printf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf("Trapped 4\n"); - - break; - } - CrossProduct (planes[0], planes[1], dir); - d = DotProduct (dir, pmove->velocity); - VectorScale (dir, d, pmove->velocity ); - } - - // - // if original velocity is against the original velocity, stop dead - // to avoid tiny occilations in sloping corners - // - if (DotProduct (pmove->velocity, primal_velocity) <= 0) - { - //Con_DPrintf("Back\n"); - VectorCopy (vec3_origin, pmove->velocity); - break; - } - } - } - - if ( allFraction == 0 ) - { - VectorCopy (vec3_origin, pmove->velocity); - //Con_DPrintf( "Don't stick\n" ); - } - - return blocked; -} - -/* -============== -PM_Accelerate -============== -*/ -void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) -{ - int i; - float addspeed, accelspeed, currentspeed; - - // Dead player's don't accelerate - if (pmove->dead) - return; - - // If waterjumping, don't accelerate - if (pmove->waterjumptime) - return; - - // See if we are changing direction a bit - currentspeed = DotProduct (pmove->velocity, wishdir); - - // Reduce wishspeed by the amount of veer. - addspeed = wishspeed - currentspeed; - - // If not going to add any speed, done. - if (addspeed <= 0) - return; - - // Determine amount of accleration. - accelspeed = accel * pmove->frametime * wishspeed * pmove->friction; - - // Cap at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // Adjust velocity. - for (i=0 ; i<3 ; i++) - { - pmove->velocity[i] += accelspeed * wishdir[i]; - } -} - -/* -===================== -PM_WalkMove - -Only used by players. Moves along the ground when player is a MOVETYPE_WALK. -====================== -*/ -void PM_WalkMove () -{ - int oldonground; - int i; - - vec3_t wishvel; - float spd; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - - vec3_t dest; //, start; - vec3_t original, originalvel; - vec3_t down, downvel; - float downdist, updist; - - pmtrace_t trace; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - // Zero out z components of movement vectors - pmove->forward[2] = 0; - pmove->right[2] = 0; - - VectorNormalize (pmove->forward); // Normalize remainder of vectors. - VectorNormalize (pmove->right); // - - for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - - wishvel[2] = 0; // Zero out z part of velocity - - VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move - wishspeed = VectorNormalize(wishdir); - -// -// Clamp to server defined max speed -// - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - - // Set pmove velocity - pmove->velocity[2] = 0; - PM_Accelerate (wishdir, wishspeed, pmove->movevars->accelerate); - pmove->velocity[2] = 0; - - // Add in any base velocity to the current velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - spd = Length( pmove->velocity ); - - if (spd < 1.0f) - { - VectorClear( pmove->velocity ); - return; - } - - // If we are not moving, do nothing - //if (!pmove->velocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) - // return; - - oldonground = pmove->onground; - -// first try just moving to the destination - dest[0] = pmove->origin[0] + pmove->velocity[0]*pmove->frametime; - dest[1] = pmove->origin[1] + pmove->velocity[1]*pmove->frametime; - dest[2] = pmove->origin[2]; - - // first try moving directly to the next spot - // VectorCopy (dest, start); - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - // If we made it all the way, then copy trace end - // as new player position. - if (trace.fraction == 1) - { - VectorCopy (trace.endpos, pmove->origin); - return; - } - - if (oldonground == -1 && // Don't walk up stairs if not on ground. - pmove->waterlevel == 0) - return; - - if (pmove->waterjumptime) // If we are jumping out of water, don't do anything more. - return; - - // Try sliding forward both on ground and up 16 pixels - // take the move that goes farthest - VectorCopy (pmove->origin, original); // Save out original pos & - VectorCopy (pmove->velocity, originalvel); // velocity. - - // Slide move - PM_FlyMove (); - - // Copy the results out - VectorCopy (pmove->origin , down); - VectorCopy (pmove->velocity, downvel); - - // Reset original values. - VectorCopy (original, pmove->origin); - - VectorCopy (originalvel, pmove->velocity); - - // Start out up one stair height - VectorCopy (pmove->origin, dest); - dest[2] += pmove->movevars->stepsize; - - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - // If we started okay and made it part of the way at least, - // copy the results to the movement start position and then - // run another move try. - if (!trace.startsolid && !trace.allsolid) - { - VectorCopy (trace.endpos, pmove->origin); - } - -// slide move the rest of the way. - PM_FlyMove (); - -// Now try going back down from the end point -// press down the stepheight - VectorCopy (pmove->origin, dest); - dest[2] -= pmove->movevars->stepsize; - - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - - // If we are not on the ground any more then - // use the original movement attempt - if ( trace.plane.normal[2] < 0.7) - goto usedown; - // If the trace ended up in empty space, copy the end - // over to the origin. - if (!trace.startsolid && !trace.allsolid) - { - VectorCopy (trace.endpos, pmove->origin); - } - // Copy this origion to up. - VectorCopy (pmove->origin, pmove->up); - - // decide which one went farther - downdist = (down[0] - original[0])*(down[0] - original[0]) - + (down[1] - original[1])*(down[1] - original[1]); - updist = (pmove->up[0] - original[0])*(pmove->up[0] - original[0]) - + (pmove->up[1] - original[1])*(pmove->up[1] - original[1]); - - if (downdist > updist) - { -usedown: - VectorCopy (down , pmove->origin); - VectorCopy (downvel, pmove->velocity); - } else // copy z value from slide move - pmove->velocity[2] = downvel[2]; - -} - -/* -================== -PM_Friction - -Handles both ground friction and water friction -================== -*/ -void PM_Friction (void) -{ - float *vel; - float speed, newspeed, control; - float friction; - float drop; - vec3_t newvel; - - // If we are in water jump cycle, don't apply friction - if (pmove->waterjumptime) - return; - - // Get velocity - vel = pmove->velocity; - - // Calculate speed - speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); - - // If too slow, return - if (speed < 0.1f) - { - return; - } - - drop = 0; - -// apply ground friction - if (pmove->onground != -1) // On an entity that is the ground - { - vec3_t start, stop; - pmtrace_t trace; - - start[0] = stop[0] = pmove->origin[0] + vel[0]/speed*16; - start[1] = stop[1] = pmove->origin[1] + vel[1]/speed*16; - start[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2]; - stop[2] = start[2] - 34; - - trace = pmove->PM_PlayerTrace (start, stop, PM_NORMAL, -1 ); - - if (trace.fraction == 1.0) - friction = pmove->movevars->friction*pmove->movevars->edgefriction; - else - friction = pmove->movevars->friction; - - // Grab friction value. - //friction = pmove->movevars->friction; - - friction *= pmove->friction; // player friction? - - // Bleed off some speed, but if we have less than the bleed - // threshhold, bleed the theshold amount. - control = (speed < pmove->movevars->stopspeed) ? - pmove->movevars->stopspeed : speed; - // Add the amount to t'he drop amount. - drop += control*friction*pmove->frametime; - } - -// apply water friction -// if (pmove->waterlevel) -// drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime; - -// scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - // Determine proportion of old speed we are using. - newspeed /= speed; - - // Adjust velocity according to proportion. - newvel[0] = vel[0] * newspeed; - newvel[1] = vel[1] * newspeed; - newvel[2] = vel[2] * newspeed; - - VectorCopy( newvel, pmove->velocity ); -} - -void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) -{ - int i; - float addspeed, accelspeed, currentspeed, wishspd = wishspeed; - - if (pmove->dead) - return; - if (pmove->waterjumptime) - return; - - // Cap speed - //wishspd = VectorNormalize (pmove->wishveloc); - - if (wishspd > 30) - wishspd = 30; - // Determine veer amount - currentspeed = DotProduct (pmove->velocity, wishdir); - // See how much to add - addspeed = wishspd - currentspeed; - // If not adding any, done. - if (addspeed <= 0) - return; - // Determine acceleration speed after acceleration - - accelspeed = accel * wishspeed * pmove->frametime * pmove->friction; - // Cap it - if (accelspeed > addspeed) - accelspeed = addspeed; - - // Adjust pmove vel. - for (i=0 ; i<3 ; i++) - { - pmove->velocity[i] += accelspeed*wishdir[i]; - } -} - -/* -=================== -PM_WaterMove - -=================== -*/ -void PM_WaterMove (void) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - vec3_t start, dest; - vec3_t temp; - pmtrace_t trace; - - float speed, newspeed, addspeed, accelspeed; - -// -// user intentions -// - for (i=0 ; i<3 ; i++) - wishvel[i] = pmove->forward[i]*pmove->cmd.forwardmove + pmove->right[i]*pmove->cmd.sidemove; - - // Sinking after no other movement occurs - if (!pmove->cmd.forwardmove && !pmove->cmd.sidemove && !pmove->cmd.upmove) - wishvel[2] -= 60; // drift towards bottom - else // Go straight up by upmove amount. - wishvel[2] += pmove->cmd.upmove; - - // Copy it over and determine speed - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // Cap speed. - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - // Slow us down a bit. - wishspeed *= 0.8; - - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); -// Water friction - VectorCopy(pmove->velocity, temp); - speed = VectorNormalize(temp); - if (speed) - { - newspeed = speed - pmove->frametime * speed * pmove->movevars->friction * pmove->friction; - - if (newspeed < 0) - newspeed = 0; - VectorScale (pmove->velocity, newspeed/speed, pmove->velocity); - } - else - newspeed = 0; - -// -// water acceleration -// - if ( wishspeed < 0.1f ) - { - return; - } - - addspeed = wishspeed - newspeed; - if (addspeed > 0) - { - - VectorNormalize(wishvel); - accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pmove->velocity[i] += accelspeed * wishvel[i]; - } - -// Now move -// assume it is a stair or a slope, so press down from stepheight above - VectorMA (pmove->origin, pmove->frametime, pmove->velocity, dest); - VectorCopy (dest, start); - start[2] += pmove->movevars->stepsize + 1; - trace = pmove->PM_PlayerTrace (start, dest, PM_NORMAL, -1 ); - if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope? - { // walked up the step, so just keep result and exit - VectorCopy (trace.endpos, pmove->origin); - return; - } - - // Try moving straight along out normal path. - PM_FlyMove (); -} - - -/* -=================== -PM_AirMove - -=================== -*/ -void PM_AirMove (void) -{ - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - // Zero out z components of movement vectors - pmove->forward[2] = 0; - pmove->right[2] = 0; - // Renormalize - VectorNormalize (pmove->forward); - VectorNormalize (pmove->right); - - // Determine x and y parts of velocity - for (i=0 ; i<2 ; i++) - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - // Zero out z part of velocity - wishvel[2] = 0; - - // Determine maginitude of speed of move - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // Clamp to server defined max speed - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - - PM_AirAccelerate (wishdir, wishspeed, pmove->movevars->airaccelerate); - - // Add in any base velocity to the current velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - PM_FlyMove (); -} - -qboolean PM_InWater( void ) -{ - return ( pmove->waterlevel > 1 ); -} - -/* -============= -PM_CheckWater - -Sets pmove->waterlevel and pmove->watertype values. -============= -*/ -qboolean PM_CheckWater () -{ - vec3_t point; - int cont; - int truecont; - float height; - float heightover2; - - // Pick a spot just above the players feet. - point[0] = pmove->origin[0] + (pmove->player_mins[pmove->usehull][0] + pmove->player_maxs[pmove->usehull][0]) * 0.5; - point[1] = pmove->origin[1] + (pmove->player_mins[pmove->usehull][1] + pmove->player_maxs[pmove->usehull][1]) * 0.5; - point[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2] + 1; - - // Assume that we are not in water at all. - pmove->waterlevel = 0; - pmove->watertype = CONTENTS_EMPTY; - - // Grab point contents. - cont = pmove->PM_PointContents (point, &truecont ); - // Are we under water? (not solid and not empty?) - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - { - // Set water type - pmove->watertype = cont; - - // We are at least at level one - pmove->waterlevel = 1; - - height = (pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2]); - heightover2 = height * 0.5; - - // Now check a point that is at the player hull midpoint. - point[2] = pmove->origin[2] + heightover2; - cont = pmove->PM_PointContents (point, NULL ); - // If that point is also under water... - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - { - // Set a higher water level. - pmove->waterlevel = 2; - - // Now check the eye position. (view_ofs is relative to the origin) - point[2] = pmove->origin[2] + pmove->view_ofs[2]; - - cont = pmove->PM_PointContents (point, NULL ); - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - pmove->waterlevel = 3; // In over our eyes - } - - // Adjust velocity based on water current, if any. - if ( ( truecont <= CONTENTS_CURRENT_0 ) && - ( truecont >= CONTENTS_CURRENT_DOWN ) ) - { - // The deeper we are, the stronger the current. - static vec3_t current_table[] = - { - {1, 0, 0}, {0, 1, 0}, {-1, 0, 0}, - {0, -1, 0}, {0, 0, 1}, {0, 0, -1} - }; - - VectorMA (pmove->basevelocity, 50.0*pmove->waterlevel, current_table[CONTENTS_CURRENT_0 - truecont], pmove->basevelocity); - } - } - - return pmove->waterlevel > 1; -} - -/* -============= -PM_CatagorizePosition -============= -*/ -void PM_CatagorizePosition (void) -{ - vec3_t point; - pmtrace_t tr; - -// if the player hull point one unit down is solid, the player -// is on ground - -// see if standing on something solid - - // Doing this before we move may introduce a potential latency in water detection, but - // doing it after can get us stuck on the bottom in water if the amount we move up - // is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call - // this several times per frame, so we really need to avoid sticking to the bottom of - // water on each call, and the converse case will correct itself if called twice. - PM_CheckWater(); - - point[0] = pmove->origin[0]; - point[1] = pmove->origin[1]; - point[2] = pmove->origin[2] - 2; - - if (pmove->velocity[2] > 180) // Shooting up really fast. Definitely not on ground. - { - pmove->onground = -1; - } - else - { - // Try and move down. - tr = pmove->PM_PlayerTrace (pmove->origin, point, PM_NORMAL, -1 ); - // If we hit a steep plane, we are not on ground - if ( tr.plane.normal[2] < 0.7) - pmove->onground = -1; // too steep - else - pmove->onground = tr.ent; // Otherwise, point to index of ent under us. - - // If we are on something... - if (pmove->onground != -1) - { - // Then we are not in water jump sequence - pmove->waterjumptime = 0; - // If we could make the move, drop us down that 1 pixel - if (pmove->waterlevel < 2 && !tr.startsolid && !tr.allsolid) - VectorCopy (tr.endpos, pmove->origin); - } - - // Standing on an entity other than the world - if (tr.ent > 0) // So signal that we are touching something. - { - PM_AddToTouched(tr, pmove->velocity); - } - } -} - -/* -================= -PM_GetRandomStuckOffsets - -When a player is stuck, it's costly to try and unstick them -Grab a test offset for the player based on a passed in index -================= -*/ -int PM_GetRandomStuckOffsets(int nIndex, int server, vec3_t offset) -{ - // Last time we did a full - int idx; - idx = rgStuckLast[nIndex][server]++; - - VectorCopy(rgv3tStuckTable[idx % 54], offset); - - return (idx % 54); -} - -void PM_ResetStuckOffsets(int nIndex, int server) -{ - rgStuckLast[nIndex][server] = 0; -} - -/* -================= -NudgePosition - -If pmove->origin is in a solid position, -try nudging slightly on all axis to -allow for the cut precision of the net coordinates -================= -*/ -#define PM_CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly. - -int PM_CheckStuck (void) -{ - vec3_t base; - vec3_t offset; - vec3_t test; - int hitent; - int idx; - float fTime; - int i; - pmtrace_t traceresult; - - static float rgStuckCheckTime[MAX_CLIENTS][2]; // Last time we did a full - - // If position is okay, exit - hitent = pmove->PM_TestPlayerPosition (pmove->origin, &traceresult ); - if (hitent == -1 ) - { - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - return 0; - } - - VectorCopy (pmove->origin, base); - - // - // Deal with precision error in network. - // - if (!pmove->server) - { - // World or BSP model - if ( ( hitent == 0 ) || - ( pmove->physents[hitent].model != NULL ) ) - { - int nReps = 0; - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - do - { - i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); - - VectorAdd(base, offset, test); - if (pmove->PM_TestPlayerPosition (test, &traceresult ) == -1) - { - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - - VectorCopy ( test, pmove->origin ); - return 0; - } - nReps++; - } while (nReps < 54); - } - } - - // Only an issue on the client. - - if (pmove->server) - idx = 0; - else - idx = 1; - - fTime = pmove->Sys_FloatTime(); - // Too soon? - if (rgStuckCheckTime[pmove->player_index][idx] >= - ( fTime - PM_CHECKSTUCK_MINTIME ) ) - { - return 1; - } - rgStuckCheckTime[pmove->player_index][idx] = fTime; - - pmove->PM_StuckTouch( hitent, &traceresult ); - - i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); - - VectorAdd(base, offset, test); - if ( ( hitent = pmove->PM_TestPlayerPosition ( test, NULL ) ) == -1 ) - { - //Con_DPrintf("Nudged\n"); - - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - - if (i >= 27) - VectorCopy ( test, pmove->origin ); - - return 0; - } - - // If player is flailing while stuck in another player ( should never happen ), then see - // if we can't "unstick" them forceably. - if ( pmove->cmd.buttons & ( IN_JUMP | IN_DUCK | IN_ATTACK ) && ( pmove->physents[ hitent ].player != 0 ) ) - { - float x, y, z; - float xystep = 8.0; - float zstep = 18.0; - float xyminmax = xystep; - float zminmax = 4 * zstep; - - for ( z = 0; z <= zminmax; z += zstep ) - { - for ( x = -xyminmax; x <= xyminmax; x += xystep ) - { - for ( y = -xyminmax; y <= xyminmax; y += xystep ) - { - VectorCopy( base, test ); - test[0] += x; - test[1] += y; - test[2] += z; - - if ( pmove->PM_TestPlayerPosition ( test, NULL ) == -1 ) - { - VectorCopy( test, pmove->origin ); - return 0; - } - } - } - } - } - - //VectorCopy (base, pmove->origin); - - return 1; -} - -/* -=============== -PM_SpectatorMove -=============== -*/ -void PM_SpectatorMove (void) -{ - float speed, drop, friction, control, newspeed; - //float accel; - float currentspeed, addspeed, accelspeed; - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - // this routine keeps track of the spectators psoition - // there a two different main move types : track player or moce freely (OBS_ROAMING) - // doesn't need excate track position, only to generate PVS, so just copy - // targets position and real view position is calculated on client (saves server CPU) - - if ( pmove->iuser1 == OBS_ROAMING) - { - -#ifdef CLIENT_DLL - // jump only in roaming mode - if ( iJumpSpectator ) - { - VectorCopy( vJumpOrigin, pmove->origin ); - VectorCopy( vJumpAngles, pmove->angles ); - VectorCopy( vec3_origin, pmove->velocity ); - iJumpSpectator = 0; - return; - } -#endif - // Move around in normal spectator method - - speed = Length (pmove->velocity); - if (speed < 1) - { - VectorCopy (vec3_origin, pmove->velocity) - } - else - { - drop = 0; - - friction = pmove->movevars->friction*1.5; // extra friction - control = speed < pmove->movevars->stopspeed ? pmove->movevars->stopspeed : speed; - drop += control*friction*pmove->frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - VectorScale (pmove->velocity, newspeed, pmove->velocity); - } - - // accelerate - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - VectorNormalize (pmove->forward); - VectorNormalize (pmove->right); - - for (i=0 ; i<3 ; i++) - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - wishvel[2] += pmove->cmd.upmove; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - if (wishspeed > pmove->movevars->spectatormaxspeed) - { - VectorScale (wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel); - wishspeed = pmove->movevars->spectatormaxspeed; - } - - currentspeed = DotProduct(pmove->velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = pmove->movevars->accelerate*pmove->frametime*wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i=0 ; i<3 ; i++) - pmove->velocity[i] += accelspeed*wishdir[i]; - - // move - VectorMA (pmove->origin, pmove->frametime, pmove->velocity, pmove->origin); - } - else - { - // all other modes just track some kind of target, so spectator PVS = target PVS - - int target; - - // no valid target ? - if ( pmove->iuser2 <= 0) - return; - - // Find the client this player's targeting - for (target = 0; target < pmove->numphysent; target++) - { - if ( pmove->physents[target].info == pmove->iuser2 ) - break; - } - - if (target == pmove->numphysent) - return; - - // use targets position as own origin for PVS - VectorCopy( pmove->physents[target].angles, pmove->angles ); - VectorCopy( pmove->physents[target].origin, pmove->origin ); - - // no velocity - VectorCopy( vec3_origin, pmove->velocity ); - } -} - -/* -================== -PM_SplineFraction - -Use for ease-in, ease-out style interpolation (accel/decel) -Used by ducking code. -================== -*/ -float PM_SplineFraction( float value, float scale ) -{ - float valueSquared; - - value = scale * value; - valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - -void PM_FixPlayerCrouchStuck( int direction ) -{ - int hitent; - int i; - vec3_t test; - - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) - return; - - VectorCopy( pmove->origin, test ); - for ( i = 0; i < 36; i++ ) - { - pmove->origin[2] += direction; - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) - return; - } - - VectorCopy( test, pmove->origin ); // Failed -} - -void PM_UnDuck( void ) -{ - int i; - pmtrace_t trace; - vec3_t newOrigin; - - VectorCopy( pmove->origin, newOrigin ); - - if ( pmove->onground != -1 ) - { - for ( i = 0; i < 3; i++ ) - { - newOrigin[i] += ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); - } - } - - trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 ); - - if ( !trace.startsolid ) - { - pmove->usehull = 0; - - // Oh, no, changing hulls stuck us into something, try unsticking downward first. - trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 ); - if ( trace.startsolid ) - { - // See if we are stuck? If so, stay ducked with the duck hull until we have a clear spot - //Con_Printf( "unstick got stuck\n" ); - pmove->usehull = 1; - return; - } - - pmove->flags &= ~FL_DUCKING; - pmove->bInDuck = false; - pmove->view_ofs[2] = VEC_VIEW; - pmove->flDuckTime = 0; - - VectorCopy( newOrigin, pmove->origin ); - - // Recatagorize position since ducking can change origin - PM_CatagorizePosition(); - } -} - -void PM_Duck( void ) -{ - int i; - float time; - float duckFraction; - - int buttonsChanged = ( pmove->oldbuttons ^ pmove->cmd.buttons ); // These buttons have changed this frame - int nButtonPressed = buttonsChanged & pmove->cmd.buttons; // The changed ones still down are "pressed" - - if ( pmove->cmd.buttons & IN_DUCK ) - { - pmove->oldbuttons |= IN_DUCK; - } - else - { - pmove->oldbuttons &= ~IN_DUCK; - } - - // Prevent ducking if the iuser3 variable is set - if ( pmove->iuser3 || pmove->dead ) - { - // Try to unduck - if ( pmove->flags & FL_DUCKING ) - { - PM_UnDuck(); - } - return; - } - - if ( pmove->flags & FL_DUCKING ) - { - pmove->cmd.forwardmove *= PLAYER_DUCKING_MULTIPLIER; - pmove->cmd.sidemove *= PLAYER_DUCKING_MULTIPLIER; - pmove->cmd.upmove *= PLAYER_DUCKING_MULTIPLIER; - } - - if ( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) - { - if ( pmove->cmd.buttons & IN_DUCK ) - { - if ( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) ) - { - // Use 1 second so super long jump will work - pmove->flDuckTime = 1000; - pmove->bInDuck = true; - } - - time = max( 0.0, ( 1.0 - (float)pmove->flDuckTime / 1000.0 ) ); - - if ( pmove->bInDuck ) - { - // Finish ducking immediately if duck time is over or not on ground - if ( ( (float)pmove->flDuckTime / 1000.0 <= ( 1.0 - TIME_TO_DUCK ) ) || - ( pmove->onground == -1 ) ) - { - pmove->usehull = 1; - pmove->view_ofs[2] = VEC_DUCK_VIEW; - pmove->flags |= FL_DUCKING; - pmove->bInDuck = false; - - // HACKHACK - Fudge for collision bug - no time to fix this properly - if ( pmove->onground != -1 ) - { - for ( i = 0; i < 3; i++ ) - { - pmove->origin[i] -= ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); - } - // See if we are stuck? - PM_FixPlayerCrouchStuck( STUCK_MOVEUP ); - - // Recatagorize position since ducking can change origin - PM_CatagorizePosition(); - } - } - else - { - float fMore = (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); - - // Calc parametric time - duckFraction = PM_SplineFraction( time, (1.0/TIME_TO_DUCK) ); - pmove->view_ofs[2] = ((VEC_DUCK_VIEW - fMore ) * duckFraction) + (VEC_VIEW * (1-duckFraction)); - } - } - } - else - { - // Try to unduck - PM_UnDuck(); - } - } -} - -void PM_LadderMove( physent_t *pLadder ) -{ - vec3_t ladderCenter; - trace_t trace; - qboolean onFloor; - vec3_t floor; - vec3_t modelmins, modelmaxs; - - if ( pmove->movetype == MOVETYPE_NOCLIP ) - return; - -#if defined( _TFC ) - // this is how TFC freezes players, so we don't want them climbing ladders - if ( pmove->maxspeed <= 1.0 ) - return; -#endif - - pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs ); - - VectorAdd( modelmins, modelmaxs, ladderCenter ); - VectorScale( ladderCenter, 0.5, ladderCenter ); - - pmove->movetype = MOVETYPE_FLY; - - // On ladder, convert movement to be relative to the ladder - - VectorCopy( pmove->origin, floor ); - floor[2] += pmove->player_mins[pmove->usehull][2] - 1; - - if ( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID ) - onFloor = true; - else - onFloor = false; - - pmove->gravity = 0; - pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace ); - if ( trace.fraction != 1.0 ) - { - float forward = 0, right = 0; - vec3_t vpn, v_right; - float flSpeed = MAX_CLIMB_SPEED; - - // they shouldn't be able to move faster than their maxspeed - if ( flSpeed > pmove->maxspeed ) - { - flSpeed = pmove->maxspeed; - } - - AngleVectors( pmove->angles, vpn, v_right, NULL ); - - if ( pmove->flags & FL_DUCKING ) - { - flSpeed *= PLAYER_DUCKING_MULTIPLIER; - } - - if ( pmove->cmd.buttons & IN_BACK ) - { - forward -= flSpeed; - } - if ( pmove->cmd.buttons & IN_FORWARD ) - { - forward += flSpeed; - } - if ( pmove->cmd.buttons & IN_MOVELEFT ) - { - right -= flSpeed; - } - if ( pmove->cmd.buttons & IN_MOVERIGHT ) - { - right += flSpeed; - } - - if ( pmove->cmd.buttons & IN_JUMP ) - { - pmove->movetype = MOVETYPE_WALK; - VectorScale( trace.plane.normal, 270, pmove->velocity ); - } - else - { - if ( forward != 0 || right != 0 ) - { - vec3_t velocity, perp, cross, lateral, tmp; - float normal; - - //ALERT(at_console, "pev %.2f %.2f %.2f - ", - // pev->velocity.x, pev->velocity.y, pev->velocity.z); - // Calculate player's intended velocity - //Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right); - VectorScale( vpn, forward, velocity ); - VectorMA( velocity, right, v_right, velocity ); - - - // Perpendicular in the ladder plane - // Vector perp = CrossProduct( Vector(0,0,1), trace.vecPlaneNormal ); - // perp = perp.Normalize(); - VectorClear( tmp ); - tmp[2] = 1; - CrossProduct( tmp, trace.plane.normal, perp ); - VectorNormalize( perp ); - - - // decompose velocity into ladder plane - normal = DotProduct( velocity, trace.plane.normal ); - // This is the velocity into the face of the ladder - VectorScale( trace.plane.normal, normal, cross ); - - - // This is the player's additional velocity - VectorSubtract( velocity, cross, lateral ); - - // This turns the velocity into the face of the ladder into velocity that - // is roughly vertically perpendicular to the face of the ladder. - // NOTE: It IS possible to face up and move down or face down and move up - // because the velocity is a sum of the directional velocity and the converted - // velocity through the face of the ladder -- by design. - CrossProduct( trace.plane.normal, perp, tmp ); - VectorMA( lateral, -normal, tmp, pmove->velocity ); - if ( onFloor && normal > 0 ) // On ground moving away from the ladder - { - VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity ); - } - //pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal); - } - else - { - VectorClear( pmove->velocity ); - } - } - } -} - -physent_t *PM_Ladder( void ) -{ - int i; - physent_t *pe; - hull_t *hull; - int num; - vec3_t test; - - for ( i = 0; i < pmove->nummoveent; i++ ) - { - pe = &pmove->moveents[i]; - - if ( pe->model && (modtype_t)pmove->PM_GetModelType( pe->model ) == mod_brush && pe->skin == CONTENTS_LADDER ) - { - - hull = (hull_t *)pmove->PM_HullForBsp( pe, test ); - num = hull->firstclipnode; - - // Offset the test point appropriately for this hull. - VectorSubtract ( pmove->origin, test, test); - - // Test the player's hull for intersection with this model - if ( pmove->PM_HullPointContents (hull, num, test) == CONTENTS_EMPTY) - continue; - - return pe; - } - } - - return NULL; -} - - - -void PM_WaterJump (void) -{ - if ( pmove->waterjumptime > 10000 ) - { - pmove->waterjumptime = 10000; - } - - if ( !pmove->waterjumptime ) - return; - - pmove->waterjumptime -= pmove->cmd.msec; - if ( pmove->waterjumptime < 0 || - !pmove->waterlevel ) - { - pmove->waterjumptime = 0; - pmove->flags &= ~FL_WATERJUMP; - } - - pmove->velocity[0] = pmove->movedir[0]; - pmove->velocity[1] = pmove->movedir[1]; -} - -/* -============ -PM_AddGravity - -============ -*/ -void PM_AddGravity () -{ - float ent_gravity; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Add gravity incorrectly - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime ); - pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; - pmove->basevelocity[2] = 0; - PM_CheckVelocity(); -} -/* -============ -PM_PushEntity - -Does not change the entities velocity at all -============ -*/ -pmtrace_t PM_PushEntity (vec3_t push) -{ - pmtrace_t trace; - vec3_t end; - - VectorAdd (pmove->origin, push, end); - - trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); - - VectorCopy (trace.endpos, pmove->origin); - - // So we can run impact function afterwards. - if (trace.fraction < 1.0 && - !trace.allsolid) - { - PM_AddToTouched(trace, pmove->velocity); - } - - return trace; -} - -/* -============ -PM_Physics_Toss() - -Dead player flying through air., e.g. -============ -*/ -void PM_Physics_Toss() -{ - pmtrace_t trace; - vec3_t move; - float backoff; - - PM_CheckWater(); - - if (pmove->velocity[2] > 0) - pmove->onground = -1; - - // If on ground and not moving, return. - if ( pmove->onground != -1 ) - { - if (VectorCompare(pmove->basevelocity, vec3_origin) && - VectorCompare(pmove->velocity, vec3_origin)) - return; - } - - PM_CheckVelocity (); - -// add gravity - if ( pmove->movetype != MOVETYPE_FLY && - pmove->movetype != MOVETYPE_BOUNCEMISSILE && - pmove->movetype != MOVETYPE_FLYMISSILE ) - PM_AddGravity (); - -// move origin - // Base velocity is not properly accounted for since this entity will move again after the bounce without - // taking it into account - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); - - PM_CheckVelocity(); - VectorScale (pmove->velocity, pmove->frametime, move); - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - - trace = PM_PushEntity (move); // Should this clear basevelocity - - PM_CheckVelocity(); - - if (trace.allsolid) - { - // entity is trapped in another solid - pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); - return; - } - - if (trace.fraction == 1) - { - PM_CheckWater(); - return; - } - - - if (pmove->movetype == MOVETYPE_BOUNCE) - backoff = 2.0 - pmove->friction; - else if (pmove->movetype == MOVETYPE_BOUNCEMISSILE) - backoff = 2.0; - else - backoff = 1; - - PM_ClipVelocity (pmove->velocity, trace.plane.normal, pmove->velocity, backoff); - - // stop if on ground - if (trace.plane.normal[2] > 0.7) - { - float vel; - vec3_t base; - - VectorClear( base ); - if (pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime) - { - // we're rolling on the ground, add static friction. - pmove->onground = trace.ent; - pmove->velocity[2] = 0; - } - - vel = DotProduct( pmove->velocity, pmove->velocity ); - - // Con_DPrintf("%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] ); - - if (vel < (30 * 30) || (pmove->movetype != MOVETYPE_BOUNCE && pmove->movetype != MOVETYPE_BOUNCEMISSILE)) - { - pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); - } - else - { - VectorScale (pmove->velocity, (1.0 - trace.fraction) * pmove->frametime * 0.9, move); - trace = PM_PushEntity (move); - } - VectorSubtract( pmove->velocity, base, pmove->velocity ) - } - -// check for in water - PM_CheckWater(); -} - -/* -==================== -PM_NoClip - -==================== -*/ -void PM_NoClip() -{ - int i; - vec3_t wishvel; - float fmove, smove; -// float currentspeed, addspeed, accelspeed; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - VectorNormalize ( pmove->forward ); - VectorNormalize ( pmove->right ); - - for (i=0 ; i<3 ; i++) // Determine x and y parts of velocity - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - wishvel[2] += pmove->cmd.upmove; - - VectorMA (pmove->origin, pmove->frametime, wishvel, pmove->origin); - - // Zero out the velocity so that we don't accumulate a huge downward velocity from - // gravity, etc. - VectorClear( pmove->velocity ); - -} - -// Only allow bunny jumping up to 1.7x server / player maxspeed setting -#define BUNNYJUMP_MAX_SPEED_FACTOR 1.7f - -//----------------------------------------------------------------------------- -// Purpose: Corrects bunny jumping ( where player initiates a bunny jump before other -// movement logic runs, thus making onground == -1 thus making PM_Friction get skipped and -// running PM_AirMove, which doesn't crop velocity to maxspeed like the ground / other -// movement logic does. -//----------------------------------------------------------------------------- -void PM_PreventMegaBunnyJumping( void ) -{ - // Current player speed - float spd; - // If we have to crop, apply this cropping fraction to velocity - float fraction; - // Speed at which bunny jumping is limited - float maxscaledspeed; - - maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * pmove->maxspeed; - - // Don't divide by zero - if ( maxscaledspeed <= 0.0f ) - return; - - spd = Length( pmove->velocity ); - - if ( spd <= maxscaledspeed ) - return; - - fraction = ( maxscaledspeed / spd ) * 0.65; //Returns the modifier for the velocity - - VectorScale( pmove->velocity, fraction, pmove->velocity ); //Crop it down!. -} - -/* -============= -PM_Jump -============= -*/ -void PM_Jump (void) -{ - int i; - qboolean tfc = false; - - qboolean cansuperjump = false; - - if (pmove->dead) - { - pmove->oldbuttons |= IN_JUMP ; // don't jump again until released - return; - } - - tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; - - // Spy that's feigning death cannot jump - if ( tfc && - ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) - { - return; - } - - // See if we are waterjumping. If so, decrement count and return. - if ( pmove->waterjumptime ) - { - pmove->waterjumptime -= pmove->cmd.msec; - if (pmove->waterjumptime < 0) - { - pmove->waterjumptime = 0; - } - return; - } - - // If we are in the water most of the way... - if (pmove->waterlevel >= 2) - { // swimming, not jumping - pmove->onground = -1; - - if (pmove->watertype == CONTENTS_WATER) // We move up a certain amount - pmove->velocity[2] = 100; - else if (pmove->watertype == CONTENTS_SLIME) - pmove->velocity[2] = 80; - else // LAVA - pmove->velocity[2] = 50; - - // play swiming sound - if ( pmove->flSwimTime <= 0 ) - { - // Don't play sound again for 1 second - pmove->flSwimTime = 1000; - switch ( pmove->RandomLong( 0, 3 ) ) - { - case 0: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 2: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 3: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - } - } - - return; - } - - // No more effect - if ( pmove->onground == -1 ) - { - // Flag that we jumped. - // HACK HACK HACK - // Remove this when the game .dll no longer does physics code!!!! - pmove->oldbuttons |= IN_JUMP; // don't jump again until released - return; // in air, so no effect - } - - if ( pmove->oldbuttons & IN_JUMP ) - return; // don't pogo stick - - // In the air now. - pmove->onground = -1; - - PM_PreventMegaBunnyJumping(); - - if ( tfc ) - { - pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); - } - else - { - PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0 ); - } - - // See if user can super long jump? - cansuperjump = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "slj" ) ) == 1 ? true : false; - - // Acclerate upward - // If we are ducking... - if ( ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) - { - // Adjust for super long jump module - // UNDONE -- note this should be based on forward angles, not current velocity. - if ( cansuperjump && - ( pmove->cmd.buttons & IN_DUCK ) && - ( pmove->flDuckTime > 0 ) && - Length( pmove->velocity ) > 50 ) - { - pmove->punchangle[0] = -5; - - for (i =0; i < 2; i++) - { - pmove->velocity[i] = pmove->forward[i] * PLAYER_LONGJUMP_SPEED * 1.6; - } - - pmove->velocity[2] = sqrt(2 * 800 * 56.0); - } - else - { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); - } - } - else - { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); - } - - // Decay it for simulation - PM_FixupGravityVelocity(); - - // Flag that we jumped. - pmove->oldbuttons |= IN_JUMP; // don't jump again until released -} - -/* -============= -PM_CheckWaterJump -============= -*/ -#define WJ_HEIGHT 8 -void PM_CheckWaterJump (void) -{ - vec3_t vecStart, vecEnd; - vec3_t flatforward; - vec3_t flatvelocity; - float curspeed; - pmtrace_t tr; - int savehull; - - // Already water jumping. - if ( pmove->waterjumptime ) - return; - - // Don't hop out if we just jumped in - if ( pmove->velocity[2] < -180 ) - return; // only hop out if we are moving up - - // See if we are backing up - flatvelocity[0] = pmove->velocity[0]; - flatvelocity[1] = pmove->velocity[1]; - flatvelocity[2] = 0; - - // Must be moving - curspeed = VectorNormalize( flatvelocity ); - - // see if near an edge - flatforward[0] = pmove->forward[0]; - flatforward[1] = pmove->forward[1]; - flatforward[2] = 0; - VectorNormalize (flatforward); - - // Are we backing into water from steps or something? If so, don't pop forward - if ( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) ) - return; - - VectorCopy( pmove->origin, vecStart ); - vecStart[2] += WJ_HEIGHT; - - VectorMA ( vecStart, 24, flatforward, vecEnd ); - - // Trace, this trace should use the point sized collision hull - savehull = pmove->usehull; - pmove->usehull = 2; - tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); - if ( tr.fraction < 1.0 && fabs( tr.plane.normal[2] ) < 0.1f ) // Facing a near vertical wall? - { - vecStart[2] += pmove->player_maxs[ savehull ][2] - WJ_HEIGHT; - VectorMA( vecStart, 24, flatforward, vecEnd ); - VectorMA( vec3_origin, -50, tr.plane.normal, pmove->movedir ); - - tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); - if ( tr.fraction == 1.0 ) - { - pmove->waterjumptime = 2000; - pmove->velocity[2] = 225; - pmove->oldbuttons |= IN_JUMP; - pmove->flags |= FL_WATERJUMP; - } - } - - // Reset the collision hull - pmove->usehull = savehull; -} - -void PM_CheckFalling( void ) -{ - if ( pmove->onground != -1 && - !pmove->dead && - pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - float fvol = 0.5; - - if ( pmove->waterlevel > 0 ) - { - } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) - { - // NOTE: In the original game dll , there were no breaks after these cases, causing the first one to - // cascade into the second - //switch ( RandomLong(0,1) ) - //{ - //case 0: - //pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - //break; - //case 1: - pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - // break; - //} - fvol = 1.0; - } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) - { - qboolean tfc = false; - tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false; - - if ( tfc ) - { - pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - } - - fvol = 0.85; - } - else if ( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED ) - { - fvol = 0; - } - - if ( fvol > 0.0 ) - { - // Play landing step right away - pmove->flTimeStepSound = 0; - - PM_UpdateStepSound(); - - // play step sound for current texture - PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), fvol ); - - // Knock the screen around a little bit, temporary effect - pmove->punchangle[ 2 ] = pmove->flFallVelocity * 0.013; // punch z axis - - if ( pmove->punchangle[ 0 ] > 8 ) - { - pmove->punchangle[ 0 ] = 8; - } - } - } - - if ( pmove->onground != -1 ) - { - pmove->flFallVelocity = 0; - } -} - -/* -================= -PM_PlayWaterSounds - -================= -*/ -void PM_PlayWaterSounds( void ) -{ - // Did we enter or leave water? - if ( ( pmove->oldwaterlevel == 0 && pmove->waterlevel != 0 ) || - ( pmove->oldwaterlevel != 0 && pmove->waterlevel == 0 ) ) - { - switch ( pmove->RandomLong(0,3) ) - { - case 0: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 2: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 3: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - } - } -} - -/* -=============== -PM_CalcRoll - -=============== -*/ -float PM_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) -{ - float sign; - float side; - float value; - vec3_t forward, right, up; - - AngleVectors (angles, forward, right, up); - - side = DotProduct (velocity, right); - - sign = side < 0 ? -1 : 1; - - side = fabs(side); - - value = rollangle; - - if (side < rollspeed) - { - side = side * value / rollspeed; - } - else - { - side = value; - } - - return side * sign; -} - -/* -============= -PM_DropPunchAngle - -============= -*/ -void PM_DropPunchAngle ( vec3_t punchangle ) -{ - float len; - - len = VectorNormalize ( punchangle ); - len -= (10.0 + len * 0.5) * pmove->frametime; - len = max( len, 0.0 ); - VectorScale ( punchangle, len, punchangle); -} - -/* -============== -PM_CheckParamters - -============== -*/ -void PM_CheckParamters( void ) -{ - float spd; - float maxspeed; - vec3_t v_angle; - - spd = ( pmove->cmd.forwardmove * pmove->cmd.forwardmove ) + - ( pmove->cmd.sidemove * pmove->cmd.sidemove ) + - ( pmove->cmd.upmove * pmove->cmd.upmove ); - spd = sqrt( spd ); - - maxspeed = pmove->clientmaxspeed; //atof( pmove->PM_Info_ValueForKey( pmove->physinfo, "maxspd" ) ); - if ( maxspeed != 0.0 ) - { - pmove->maxspeed = min( maxspeed, pmove->maxspeed ); - } - - if ( ( spd != 0.0 ) && - ( spd > pmove->maxspeed ) ) - { - float fRatio = pmove->maxspeed / spd; - pmove->cmd.forwardmove *= fRatio; - pmove->cmd.sidemove *= fRatio; - pmove->cmd.upmove *= fRatio; - } - - if ( pmove->flags & FL_FROZEN || - pmove->flags & FL_ONTRAIN || - pmove->dead ) - { - pmove->cmd.forwardmove = 0; - pmove->cmd.sidemove = 0; - pmove->cmd.upmove = 0; - } - - - PM_DropPunchAngle( pmove->punchangle ); - - // Take angles from command. - if ( !pmove->dead ) - { - VectorCopy ( pmove->cmd.viewangles, v_angle ); - VectorAdd( v_angle, pmove->punchangle, v_angle ); - - // Set up view angles. - pmove->angles[ROLL] = PM_CalcRoll ( v_angle, pmove->velocity, pmove->movevars->rollangle, pmove->movevars->rollspeed )*4; - pmove->angles[PITCH] = v_angle[PITCH]; - pmove->angles[YAW] = v_angle[YAW]; - } - else - { - VectorCopy( pmove->oldangles, pmove->angles ); - } - - // Set dead player view_offset - if ( pmove->dead ) - { - pmove->view_ofs[2] = PM_DEAD_VIEWHEIGHT; - } - - // Adjust client view angles to match values used on server. - if (pmove->angles[YAW] > 180.0f) - { - pmove->angles[YAW] -= 360.0f; - } - -} - -void PM_ReduceTimers( void ) -{ - if ( pmove->flTimeStepSound > 0 ) - { - pmove->flTimeStepSound -= pmove->cmd.msec; - if ( pmove->flTimeStepSound < 0 ) - { - pmove->flTimeStepSound = 0; - } - } - if ( pmove->flDuckTime > 0 ) - { - pmove->flDuckTime -= pmove->cmd.msec; - if ( pmove->flDuckTime < 0 ) - { - pmove->flDuckTime = 0; - } - } - if ( pmove->flSwimTime > 0 ) - { - pmove->flSwimTime -= pmove->cmd.msec; - if ( pmove->flSwimTime < 0 ) - { - pmove->flSwimTime = 0; - } - } -} - -/* -============= -PlayerMove - -Returns with origin, angles, and velocity modified in place. - -Numtouch and touchindex[] will be set if any of the physents -were contacted during the move. -============= -*/ -void PM_PlayerMove ( qboolean server ) -{ - physent_t *pLadder = NULL; - - // Are we running server code? - pmove->server = server; - - // Adjust speeds etc. - PM_CheckParamters(); - - // Assume we don't touch anything - pmove->numtouch = 0; - - // # of msec to apply movement - pmove->frametime = pmove->cmd.msec * 0.001; - - PM_ReduceTimers(); - - // Convert view angles to vectors - AngleVectors (pmove->angles, pmove->forward, pmove->right, pmove->up); - - // PM_ShowClipBox(); - - // Special handling for spectator and observers. (iuser1 is set if the player's in observer mode) - if ( pmove->spectator || pmove->iuser1 > 0 ) - { - PM_SpectatorMove(); - PM_CatagorizePosition(); - return; - } - - // Always try and unstick us unless we are in NOCLIP mode - if ( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE ) - { - if ( PM_CheckStuck() ) - { - return; // Can't move, we're stuck - } - } - - // Now that we are "unstuck", see where we are ( waterlevel and type, pmove->onground ). - PM_CatagorizePosition(); - - // Store off the starting water level - pmove->oldwaterlevel = pmove->waterlevel; - - // If we are not on ground, store off how fast we are moving down - if ( pmove->onground == -1 ) - { - pmove->flFallVelocity = -pmove->velocity[2]; - } - - g_onladder = 0; - // Don't run ladder code if dead or on a train - if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) - { - pLadder = PM_Ladder(); - if ( pLadder ) - { - g_onladder = 1; - } - } - - PM_UpdateStepSound(); - - PM_Duck(); - - // Don't run ladder code if dead or on a train - if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) - { - if ( pLadder ) - { - PM_LadderMove( pLadder ); - } - else if ( pmove->movetype != MOVETYPE_WALK && - pmove->movetype != MOVETYPE_NOCLIP ) - { - // Clear ladder stuff unless player is noclipping - // it will be set immediately again next frame if necessary - pmove->movetype = MOVETYPE_WALK; - } - } - -#if !defined( _TFC ) - // Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground - if ( ( pmove->onground != -1 ) && ( pmove->cmd.buttons & IN_USE) ) - { - VectorScale( pmove->velocity, 0.3, pmove->velocity ); - } -#endif - - // Handle movement - switch ( pmove->movetype ) - { - default: - pmove->Con_DPrintf("Bogus pmove player movetype %i on (%i) 0=cl 1=sv\n", pmove->movetype, pmove->server); - break; - - case MOVETYPE_NONE: - break; - - case MOVETYPE_NOCLIP: - PM_NoClip(); - break; - - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - PM_Physics_Toss(); - break; - - case MOVETYPE_FLY: - - PM_CheckWater(); - - // Was jump button pressed? - // If so, set velocity to 270 away from ladder. This is currently wrong. - // Also, set MOVE_TYPE to walk, too. - if ( pmove->cmd.buttons & IN_JUMP ) - { - if ( !pLadder ) - { - PM_Jump (); - } - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Perform the move accounting for any base velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); - PM_FlyMove (); - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - break; - - case MOVETYPE_WALK: - if ( !PM_InWater() ) - { - PM_AddCorrectGravity(); - } - - // If we are leaping out of the water, just update the counters. - if ( pmove->waterjumptime ) - { - PM_WaterJump(); - PM_FlyMove(); - - // Make sure waterlevel is set correctly - PM_CheckWater(); - return; - } - - // If we are swimming in the water, see if we are nudging against a place we can jump up out - // of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0 - if ( pmove->waterlevel >= 2 ) - { - if ( pmove->waterlevel == 2 ) - { - PM_CheckWaterJump(); - } - - // If we are falling again, then we must not trying to jump out of water any more. - if ( pmove->velocity[2] < 0 && pmove->waterjumptime ) - { - pmove->waterjumptime = 0; - } - - // Was jump button pressed? - if (pmove->cmd.buttons & IN_JUMP) - { - PM_Jump (); - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Perform regular water movement - PM_WaterMove(); - - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - - // Get a final position - PM_CatagorizePosition(); - } - else - - // Not underwater - { - // Was jump button pressed? - if ( pmove->cmd.buttons & IN_JUMP ) - { - if ( !pLadder ) - { - PM_Jump (); - } - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Fricion is handled before we add in any base velocity. That way, if we are on a conveyor, - // we don't slow when standing still, relative to the conveyor. - if ( pmove->onground != -1 ) - { - pmove->velocity[2] = 0.0; - PM_Friction(); - } - - // Make sure velocity is valid. - PM_CheckVelocity(); - - // Are we on ground now - if ( pmove->onground != -1 ) - { - PM_WalkMove(); - } - else - { - PM_AirMove(); // Take into account movement when in air. - } - - // Set final flags. - PM_CatagorizePosition(); - - // Now pull the base velocity back out. - // Base velocity is set if you are on a moving object, like - // a conveyor (or maybe another monster?) - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - // Make sure velocity is valid. - PM_CheckVelocity(); - - // Add any remaining gravitational component. - if ( !PM_InWater() ) - { - PM_FixupGravityVelocity(); - } - - // If we are on ground, no downward velocity. - if ( pmove->onground != -1 ) - { - pmove->velocity[2] = 0; - } - - // See if we landed on the ground with enough force to play - // a landing sound. - PM_CheckFalling(); - } - - // Did we enter or leave the water? - PM_PlayWaterSounds(); - break; - } -} - -void PM_CreateStuckTable( void ) -{ - float x, y, z; - int idx; - int i; - float zi[3]; - - memset(rgv3tStuckTable, 0, 54 * sizeof(vec3_t)); - - idx = 0; - // Little Moves. - x = y = 0; - // Z moves - for (z = -0.125 ; z <= 0.125 ; z += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - x = z = 0; - // Y moves - for (y = -0.125 ; y <= 0.125 ; y += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - y = z = 0; - // X moves - for (x = -0.125 ; x <= 0.125 ; x += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - // Remaining multi axis nudges. - for ( x = - 0.125; x <= 0.125; x += 0.250 ) - { - for ( y = - 0.125; y <= 0.125; y += 0.250 ) - { - for ( z = - 0.125; z <= 0.125; z += 0.250 ) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - } - } - - // Big Moves. - x = y = 0; - zi[0] = 0.0f; - zi[1] = 1.0f; - zi[2] = 6.0f; - - for (i = 0; i < 3; i++) - { - // Z moves - z = zi[i]; - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - x = z = 0; - - // Y moves - for (y = -2.0f ; y <= 2.0f ; y += 2.0) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - y = z = 0; - // X moves - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - // Remaining multi axis nudges. - for (i = 0 ; i < 3; i++) - { - z = zi[i]; - - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) - { - for (y = -2.0f ; y <= 2.0f ; y += 2.0) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - } - } -} - - - -/* -This modume implements the shared player physics code between any particular game and -the engine. The same PM_Move routine is built into the game .dll and the client .dll and is -invoked by each side as appropriate. There should be no distinction, internally, between server -and client. This will ensure that prediction behaves appropriately. -*/ - -void PM_Move ( struct playermove_s *ppmove, int server ) -{ - assert( pm_shared_initialized ); - - pmove = ppmove; - - PM_PlayerMove( ( server != 0 ) ? true : false ); - - if ( pmove->onground != -1 ) - { - pmove->flags |= FL_ONGROUND; - } - else - { - pmove->flags &= ~FL_ONGROUND; - } - - // In single player, reset friction after each movement to FrictionModifier Triggers work still. - if ( !pmove->multiplayer && ( pmove->movetype == MOVETYPE_WALK ) ) - { - pmove->friction = 1.0f; - } -} - -int PM_GetVisEntInfo( int ent ) -{ - if ( ent >= 0 && ent <= pmove->numvisent ) - { - return pmove->visents[ ent ].info; - } - return -1; -} - -int PM_GetPhysEntInfo( int ent ) -{ - if ( ent >= 0 && ent <= pmove->numphysent) - { - return pmove->physents[ ent ].info; - } - return -1; -} - -void PM_Init( struct playermove_s *ppmove ) -{ - assert( !pm_shared_initialized ); - - pmove = ppmove; - - PM_CreateStuckTable(); - PM_InitTextureTypes(); - - pm_shared_initialized = 1; -} diff --git a/sdk/pm_shared/pm_shared.h b/sdk/pm_shared/pm_shared.h deleted file mode 100644 index 153c539..0000000 --- a/sdk/pm_shared/pm_shared.h +++ /dev/null @@ -1,40 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -// -// pm_shared.h -// -#if !defined( PM_SHAREDH ) -#define PM_SHAREDH -#ifdef _WIN32 -#ifndef __MINGW32__ -#pragma once -#endif /* not __MINGW32__ */ -#endif - -void PM_Init( struct playermove_s *ppmove ); -void PM_Move ( struct playermove_s *ppmove, int server ); -char PM_FindTextureType( char *name ); - -// Spectator Movement modes (stored in pev->iuser1, so the physics code can get at them) -#define OBS_NONE 0 -#define OBS_CHASE_LOCKED 1 -#define OBS_CHASE_FREE 2 -#define OBS_ROAMING 3 -#define OBS_IN_EYE 4 -#define OBS_MAP_FREE 5 -#define OBS_MAP_CHASE 6 - -#endif diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..3969a27 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'metamod' +include 'metamod' diff --git a/shared.gradle b/shared.gradle new file mode 100644 index 0000000..cc61691 --- /dev/null +++ b/shared.gradle @@ -0,0 +1,33 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeExecutableBinarySpec +import org.gradle.nativeplatform.SharedLibraryBinarySpec +import org.gradle.nativeplatform.StaticLibraryBinarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply from: 'shared_msvc.gradle' +apply from: 'shared_icc.gradle' + +rootProject.ext.createToolchainConfig = { NativeBinarySpec bin -> + BinaryKind binaryKind + if (bin instanceof NativeExecutableBinarySpec) { + binaryKind = BinaryKind.EXECUTABLE + } else if (bin instanceof SharedLibraryBinarySpec) { + binaryKind = BinaryKind.SHARED_LIBRARY + } else if (bin instanceof StaticLibraryBinarySpec) { + binaryKind = BinaryKind.STATIC_LIBRARY + } else { + throw new RuntimeException("Unknown executable kind ${bin.class.name}") + } + + boolean releaseBuild = bin.buildType.name.toLowerCase() == 'release' + + if (bin.toolChain instanceof VisualCpp) { + return rootProject.createMsvcConfig(releaseBuild, binaryKind) + } else if (bin.toolChain instanceof Icc) { + return rootProject.createIccConfig(releaseBuild, binaryKind) + } else { + throw new RuntimeException("Unknown native toolchain: ${bin.toolChain.class.name}") + } +} diff --git a/shared_icc.gradle b/shared_icc.gradle new file mode 100644 index 0000000..9fb7e9d --- /dev/null +++ b/shared_icc.gradle @@ -0,0 +1,66 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.gcc.OptimizationLevel + +rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind -> + GccToolchainConfig cfg + if (release) { + cfg = new GccToolchainConfig( + compilerOptions: new GccToolchainConfig.CompilerOptions( + optimizationLevel: OptimizationLevel.LEVEL_3, + stackProtector: false, + interProceduralOptimizations: true, + noBuiltIn: true, + intelExtensions: false, + asmBlocks: true, + positionIndependentCode: false, + + extraDefines: [ + 'linux': null, + '__linux__': null, + 'NDEBUG': null + ] + ), + + linkerOptions: new GccToolchainConfig.LinkerOptions( + interProceduralOptimizations: true, + stripSymbolTable: true, + staticLibGcc: true, + staticIntel: true, + ), + + librarianOptions: new GccToolchainConfig.LibrarianOptions( + ) + ) + } else { + //debug + cfg = new GccToolchainConfig( + compilerOptions: new GccToolchainConfig.CompilerOptions( + optimizationLevel: OptimizationLevel.DISABLE, + stackProtector: true, + interProceduralOptimizations: false, + noBuiltIn: true, + intelExtensions: false, + asmBlocks: true, + + extraDefines: [ + 'linux': null, + '__linux__': null, + 'NDEBUG': null + ] + ), + + linkerOptions: new GccToolchainConfig.LinkerOptions( + interProceduralOptimizations: false, + stripSymbolTable: false, + staticLibGcc: true, + staticIntel: true, + ), + + librarianOptions: new GccToolchainConfig.LibrarianOptions( + ) + ) + } + + return cfg; +} diff --git a/shared_msvc.gradle b/shared_msvc.gradle new file mode 100644 index 0000000..254b63b --- /dev/null +++ b/shared_msvc.gradle @@ -0,0 +1,125 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.msvc.CallingConvention +import org.doomedsociety.gradlecpp.msvc.CodeGenerationKind +import org.doomedsociety.gradlecpp.msvc.CppExceptions +import org.doomedsociety.gradlecpp.msvc.DebugInfoFormat +import org.doomedsociety.gradlecpp.msvc.EnhancedInstructionsSet +import org.doomedsociety.gradlecpp.msvc.ErrorReporting +import org.doomedsociety.gradlecpp.msvc.FloatingPointModel +import org.doomedsociety.gradlecpp.msvc.LinkTimeCodeGenKind +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.msvc.OptimizationLevel +import org.doomedsociety.gradlecpp.msvc.RuntimeChecks +import org.doomedsociety.gradlecpp.msvc.WarningLevel + +rootProject.ext.createMsvcConfig = { boolean release, BinaryKind binKind -> + MsvcToolchainConfig cfg + if (release) { + cfg = new MsvcToolchainConfig( + compilerOptions: new MsvcToolchainConfig.CompilerOptions( + codeGeneration: CodeGenerationKind.MULTITHREADED, + optimizationLevel: OptimizationLevel.FULL_OPTIMIZATION, + debugInfoFormat: DebugInfoFormat.PROGRAM_DATABASE, + runtimeChecks: RuntimeChecks.DEFAULT, + cppExceptions: CppExceptions.DISABLED, + warningLevel: WarningLevel.LEVEL_3, + callingConvention: CallingConvention.CDECL, + enhancedInstructionsSet: EnhancedInstructionsSet.SSE2, + floatingPointModel: FloatingPointModel.FAST, + + enableMinimalRebuild: false, + omitFramePointers: true, + wholeProgramOptimization: true, + enabledFunctionLevelLinking: true, + enableSecurityCheck: false, + analyzeCode: false, + sdlChecks: false, + treatWarningsAsErrors: false, + treatWchartAsBuiltin: true, + forceConformanceInForLoopScope: true, + + extraDefines: [ + 'WIN32': null, + '_MBCS': null, + 'NDEBUG': null, + 'NOMINMAX': null + ] + ), + + linkerOptions: new MsvcToolchainConfig.LinkerOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG, + errorReportingMode: ErrorReporting.NO_ERROR_REPORT, + + enableIncrementalLinking: false, + eliminateUnusedRefs: true, + enableCOMDATFolding: true, + generateDebugInfo: true, + dataExecutionPrevention: true, + randomizedBaseAddress: true + ), + + librarianOptions: new MsvcToolchainConfig.LibrarianOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG + ), + + generatePdb: true + ) + } else { + //debug + cfg = new MsvcToolchainConfig( + compilerOptions: new MsvcToolchainConfig.CompilerOptions( + codeGeneration: CodeGenerationKind.MULTITHREADED_DEBUG, + optimizationLevel: OptimizationLevel.DISABLED, + debugInfoFormat: DebugInfoFormat.PROGRAM_DATABASE, + runtimeChecks: RuntimeChecks.DEFAULT, + cppExceptions: CppExceptions.ENABLED_WITH_SEH, + warningLevel: WarningLevel.LEVEL_3, + callingConvention: CallingConvention.CDECL, + enhancedInstructionsSet: EnhancedInstructionsSet.SSE2, + floatingPointModel: FloatingPointModel.FAST, + + enableMinimalRebuild: true, + omitFramePointers: false, + wholeProgramOptimization: false, + enabledFunctionLevelLinking: true, + enableSecurityCheck: true, + analyzeCode: false, + sdlChecks: false, + treatWarningsAsErrors: false, + treatWchartAsBuiltin: true, + forceConformanceInForLoopScope: true, + + extraDefines: [ + 'WIN32': null, + '_MBCS': null, + '_DEBUG': null, + 'NOMINMAX': null, + ] + ), + + linkerOptions: new MsvcToolchainConfig.LinkerOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.DEFAULT, + errorReportingMode: ErrorReporting.NO_ERROR_REPORT, + + enableIncrementalLinking: true, + eliminateUnusedRefs: false, + enableCOMDATFolding: false, + generateDebugInfo: true, + dataExecutionPrevention: true, + randomizedBaseAddress: true + ), + + librarianOptions: new MsvcToolchainConfig.LibrarianOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG + ), + + generatePdb: true + ) + + if (binKind == BinaryKind.STATIC_LIBRARY) { + cfg.compilerConfig.extraDefines['_LIB'] = null + } + } + + return cfg +} diff --git a/src/asmlib.h b/src/asmlib.h deleted file mode 100644 index d95d13d..0000000 --- a/src/asmlib.h +++ /dev/null @@ -1,224 +0,0 @@ -/*************************** asmlib.h *************************************** -* Author: Agner Fog -* Date created: 2003-12-12 -* Last modified: 2013-10-04 -* Project: asmlib.zip -* Source URL: www.agner.org/optimize -* -* Description: -* Header file for the asmlib function library. -* This library is available in many versions for different platforms. -* See asmlib-instructions.pdf for details. -* -* (c) Copyright 2003 - 2013 by Agner Fog. -* GNU General Public License http://www.gnu.org/licenses/gpl.html -*****************************************************************************/ - - -#ifndef ASMLIB_H -#define ASMLIB_H - - -/*********************************************************************** -Define compiler-specific types and directives -***********************************************************************/ - -// Define type size_t -#ifndef _SIZE_T_DEFINED -#include "stddef.h" -#endif - -// Define integer types with known size: int32_t, uint32_t, int64_t, uint64_t. -// If this doesn't work then insert compiler-specific definitions here: -#if defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1600) - // Compilers supporting C99 or C++0x have stdint.h defining these integer types - #include - #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers -#elif defined(_MSC_VER) - // Older Microsoft compilers have their own definition - typedef signed __int16 int16_t; - typedef unsigned __int16 uint16_t; - typedef signed __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef signed __int64 int64_t; - typedef unsigned __int64 uint64_t; - #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers -#else - // This works with most compilers - typedef signed short int int16_t; - typedef unsigned short int uint16_t; - typedef signed int int32_t; - typedef unsigned int uint32_t; - typedef long long int64_t; - typedef unsigned long long uint64_t; - #define INT64_SUPPORTED // Remove this if the compiler doesn't support 64-bit integers -#endif - - -// Turn off name mangling -#ifdef __cplusplus -extern "C" { -#endif - -/*********************************************************************** -Function prototypes, memory and string functions -***********************************************************************/ -void * A_memcpy (void * dest, const void * src, size_t count); // Copy count bytes from src to dest -void * A_memmove(void * dest, const void * src, size_t count); // Same as memcpy, allows overlap between src and dest -void * A_memset (void * dest, int c, size_t count); // Set count bytes in dest to (char)c -int A_memcmp (const void * buf1, const void * buf2, size_t num); // Compares two blocks of memory -size_t GetMemcpyCacheLimit(void); // Data blocks bigger than this will be copied uncached by memcpy and memmove -void SetMemcpyCacheLimit(size_t); // Change limit in GetMemcpyCacheLimit -size_t GetMemsetCacheLimit(void); // Data blocks bigger than this will be stored uncached by memset -void SetMemsetCacheLimit(size_t); // Change limit in GetMemsetCacheLimit -char * A_strcat (char * dest, const char * src); // Concatenate strings dest and src. Store result in dest -char * A_strcpy (char * dest, const char * src); // Copy string src to dest -size_t A_strlen (const char * str); // Get length of zero-terminated string -int A_strcmp (const char * a, const char * b); // Compare strings. Case sensitive -int A_stricmp (const char *string1, const char *string2); // Compare strings. Case insensitive for A-Z only -char * A_strstr (char * haystack, const char * needle); // Search for substring in string -void A_strtolower(char * string); // Convert string to lower case for A-Z only -void A_strtoupper(char * string); // Convert string to upper case for a-z only -size_t A_substring(char * dest, const char * source, size_t pos, size_t len); // Copy a substring for source into dest -size_t A_strspn (const char * str, const char * set); // Find span of characters that belong to set -size_t A_strcspn(const char * str, const char * set); // Find span of characters that don't belong to set -size_t strCountInSet(const char * str, const char * set); // Count characters that belong to set -size_t strcount_UTF8(const char * str); // Counts the number of characters in a UTF-8 encoded string - - -/*********************************************************************** -Function prototypes, miscellaneous functions -***********************************************************************/ -uint32_t A_popcount(uint32_t x); // Count 1-bits in 32-bit integer -int RoundD (double x); // Round to nearest or even -int RoundF (float x); // Round to nearest or even -int InstructionSet(void); // Tell which instruction set is supported -char * ProcessorName(void); // ASCIIZ text describing microprocessor -void CpuType(int * vendor, int * family, int * model); // Get CPU vendor, family and model -size_t DataCacheSize(int level); // Get size of data cache -void A_DebugBreak(void); // Makes a debug breakpoint -#ifdef INT64_SUPPORTED - uint64_t ReadTSC(void); // Read microprocessor internal clock (64 bits) -#else - uint32_t ReadTSC(void); // Read microprocessor internal clock (only 32 bits supported by compiler) -#endif -void cpuid_ex (int abcd[4], int eax, int ecx); // call CPUID instruction -static inline void cpuid_abcd (int abcd[4], int eax) { - cpuid_ex(abcd, eax, 0);} - -#ifdef __cplusplus -} // end of extern "C" - -// Define overloaded versions if compiling as C++ - -static inline int Round (double x) { // Overload name Round - return RoundD(x);} -static inline int Round (float x) { // Overload name Round - return RoundF(x);} -static inline const char * A_strstr(const char * haystack, const char * needle) { - return A_strstr((char*)haystack, needle);} // Overload A_strstr with const char * version - -#endif // __cplusplus - - -/*********************************************************************** -Function prototypes, integer division functions -***********************************************************************/ - -// Turn off name mangling -#ifdef __cplusplus -extern "C" { -#endif - -void setdivisori32(int buffer[2], int d); // Set divisor for repeated division -int dividefixedi32(const int buffer[2], int x); // Fast division with previously set divisor -void setdivisoru32(uint32_t buffer[2], uint32_t d); // Set divisor for repeated division -uint32_t dividefixedu32(const uint32_t buffer[2], uint32_t x); // Fast division with previously set divisor - -// Test if emmintrin.h is included and __m128i defined -#if defined(__GNUC__) && defined(_EMMINTRIN_H_INCLUDED) && !defined(__SSE2__) -#error Please compile with -sse2 or higher -#endif - -#if defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) -#define VECTORDIVISIONDEFINED - -// Integer vector division functions. These functions divide an integer vector by a scalar: - -// Set divisor for repeated integer vector division -void setdivisorV8i16(__m128i buf[2], int16_t d); // Set divisor for repeated division -void setdivisorV8u16(__m128i buf[2], uint16_t d); // Set divisor for repeated division -void setdivisorV4i32(__m128i buf[2], int32_t d); // Set divisor for repeated division -void setdivisorV4u32(__m128i buf[2], uint32_t d); // Set divisor for repeated division - -// Fast division of vector by previously set divisor -__m128i dividefixedV8i16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV8u16(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV4i32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor -__m128i dividefixedV4u32(const __m128i buf[2], __m128i x); // Fast division with previously set divisor - -#endif // defined(_INCLUDED_EMM) || (defined(_EMMINTRIN_H_INCLUDED) && defined(__SSE2__)) - -#ifdef __cplusplus -} // end of extern "C" -#endif // __cplusplus - -#ifdef __cplusplus - -// Define classes and operator '/' for fast division with fixed divisor -class div_i32; -class div_u32; -static inline int32_t operator / (int32_t x, div_i32 const &D); -static inline uint32_t operator / (uint32_t x, div_u32 const & D); - -class div_i32 { // Signed 32 bit integer division -public: - div_i32() { // Default constructor - buffer[0] = buffer[1] = 0; - } - div_i32(int d) { // Constructor with divisor - setdivisor(d); - } - void setdivisor(int d) { // Set divisor - setdivisori32(buffer, d); - } -protected: - int buffer[2]; // Internal memory - friend int32_t operator / (int32_t x, div_i32 const & D); -}; - -static inline int32_t operator / (int32_t x, div_i32 const &D){// Overloaded operator '/' - return dividefixedi32(D.buffer, x); -} - -static inline int32_t operator /= (int32_t &x, div_i32 const &D){// Overloaded operator '/=' - return x = x / D; -} - -class div_u32 { // Unsigned 32 bit integer division -public: - div_u32() { // Default constructor - buffer[0] = buffer[1] = 0; - } - div_u32(uint32_t d) { // Constructor with divisor - setdivisor(d); - } - void setdivisor(uint32_t d) { // Set divisor - setdivisoru32(buffer, d); - } -protected: - uint32_t buffer[2]; // Internal memory - friend uint32_t operator / (uint32_t x, div_u32 const & D); -}; - -static inline uint32_t operator / (uint32_t x, div_u32 const & D){ // Overloaded operator '/' - return dividefixedu32(D.buffer, x); -} - -static inline uint32_t operator /= (uint32_t &x, div_u32 const &D){// Overloaded operator '/=' - return x = x / D; -} - -#endif // __cplusplus - -#endif // ASMLIB_H diff --git a/src/commands_meta.h b/src/commands_meta.h deleted file mode 100644 index 6d433d6..0000000 --- a/src/commands_meta.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef COMMANDS_META_H -#define COMMANDS_META_H - -#include "types_meta.h" // mBOOL -#include "comp_dep.h" - -// Flags to use for meta_cmd_doplug(), to operate on existing plugins; note -// "load" operates on a non-existing plugin thus isn't included here. -typedef enum { - PC_NULL = 0, - PC_PAUSE, // pause the plugin - PC_UNPAUSE, // unpause the plugin - PC_UNLOAD, // unload the plugin - PC_RELOAD, // unload the plugin and load it again - PC_RETRY, // retry a failed operation (usually load/attach) - PC_INFO, // show all info about the plugin - PC_CLEAR, // remove a failed plugin from the list - PC_FORCE_UNLOAD, // forcibly unload the plugin - PC_REQUIRE, // require that this plugin is loaded/running -} PLUG_CMD; - -void DLLINTERNAL meta_register_cmdcvar(); - -void DLLHIDDEN svr_meta(void); // only hidden because called from outside! - -void DLLINTERNAL cmd_meta_usage(void); -void DLLINTERNAL cmd_meta_version(void); -void DLLINTERNAL cmd_meta_gpl(void); - -void DLLINTERNAL cmd_meta_game(void); -void DLLINTERNAL cmd_meta_refresh(void); -void DLLINTERNAL cmd_meta_load(void); - -void DLLINTERNAL cmd_meta_pluginlist(void); -void DLLINTERNAL cmd_meta_cmdlist(void); -void DLLINTERNAL cmd_meta_cvarlist(void); -void DLLINTERNAL cmd_meta_config(void); - -void DLLINTERNAL cmd_doplug(PLUG_CMD pcmd); - -void DLLINTERNAL client_meta(edict_t *pEntity); -void DLLINTERNAL client_meta_usage(edict_t *pEntity); -void DLLINTERNAL client_meta_version(edict_t *pEntity); -void DLLINTERNAL client_meta_pluginlist(edict_t *pEntity); -void DLLINTERNAL client_meta_aybabtu(edict_t *pEntity); - -#endif /* COMMANDS_META_H */ diff --git a/src/conf_meta.cpp b/src/conf_meta.cpp deleted file mode 100644 index 04f2dcb..0000000 --- a/src/conf_meta.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include // FILE, -#include // atoi -#include // isdigit -#include // always -#include "conf_meta.h" // me -#include "support_meta.h" // strmatch -#include "osdep.h" // strtok, - -MConfig::MConfig(void) - : list(NULL), filename(NULL), debuglevel(0), gamedll(NULL), - plugins_file(NULL), exec_cfg(NULL) -{ -} - -// Initialize default values from the stored options struct. Has to happen -// _after_ constructor, so that all the fields are allocated (d'oh). -void DLLINTERNAL MConfig::init(option_t *global_options) { - option_t *optp; - list=global_options; - for(optp=list; optp->name; optp++) - set(optp, optp->init); -} - -option_t * DLLINTERNAL MConfig::find(const char *lookup) { - option_t *optp; - - for(optp=list; optp->name && !strmatch(optp->name, lookup); optp++); - if(optp->name) - return(optp); - else - RETURN_ERRNO(NULL, ME_NOTFOUND); -} - -mBOOL DLLINTERNAL MConfig::set(const char *key, const char *value) { - option_t *optp; - optp=find(key); - if(optp) - return(set(optp, value)); - else - RETURN_ERRNO(mFALSE, ME_NOTFOUND); -} - -mBOOL DLLINTERNAL MConfig::set(option_t *setp, const char *setstr) { - char pathbuf[PATH_MAX]; - int *optval = (int *) setp->dest; - char **optstr = (char **) setp->dest; - // cvar_t *optcvar = (cvar_t *) setp->dest; - // SETOPT_FN optcmd = (SETOPT_FN) setp->dest; - - if(!setstr) - return(mTRUE); - - switch(setp->type) { - case CF_INT: - if(!isdigit(setstr[0])) { - META_WARNING("option '%s' invalid format '%s'", setp->name, setstr); - RETURN_ERRNO(mFALSE, ME_FORMAT); - } - *optval=atoi(setstr); - META_DEBUG(3, ("set config int: %s = %d", setp->name, *optval)); - break; - case CF_BOOL: - if(strcasematch(setstr, "true") - || strcasematch(setstr, "yes") - || strmatch(setstr, "1")) - { - *optval=1; - } - else if(strcasematch(setstr, "false") - || strcasematch(setstr, "no") - || strmatch(setstr, "0")) - { - *optval=0; - } - else { - META_WARNING("option '%s' invalid format '%s'", setp->name, setstr); - RETURN_ERRNO(mFALSE, ME_FORMAT); - } - META_DEBUG(3, ("set config bool: %s = %s", setp->name, *optval ? "true" : "false")); - break; - case CF_STR: - if(*optstr) - free(*optstr); - *optstr=strdup(setstr); - META_DEBUG(3, ("set config string: %s = %s", setp->name, *optstr)); - break; - case CF_PATH: - if(*optstr) - free(*optstr); - full_gamedir_path(setstr, pathbuf); - *optstr=strdup(pathbuf); - META_DEBUG(3, ("set config path: %s = %s", setp->name, *optstr)); - break; -#if 0 - case CF_CVAR: - CVAR_SET_STRING(optcvar->name, setstr); - META_DEBUG(3, ("set config cvar: %s = %s", optcvar->name, setstr)); - break; - case CF_CMD: - optcmd(setp->name, setstr); - META_DEBUG(3, ("set config command: %s, %s", optcvar->name, setstr)); - break; -#endif - default: - META_WARNING("unrecognized config type '%d'", setp->type); - RETURN_ERRNO(mFALSE, ME_ARGUMENT); - } - return(mTRUE); -} - -mBOOL DLLINTERNAL MConfig::load(const char *fn) { - FILE *fp; - char loadfile[PATH_MAX]; - char line[MAX_CONF_LEN]; - char *optname, *optval; - option_t *optp; - int ln; - - // Make full pathname (from gamedir if relative, collapse "..", - // backslashes, etc). - full_gamedir_path(fn, loadfile); - - fp=fopen(loadfile, "r"); - if(!fp) { - META_WARNING("unable to open config file '%s': %s", loadfile, - strerror(errno)); - RETURN_ERRNO(mFALSE, ME_NOFILE); - } - - META_DEBUG(2, ("Loading from config file: %s", loadfile)); - for(ln=1; !feof(fp) && fgets(line, sizeof(line), fp); ln++) { - if(line[0]=='#') - continue; - if(line[0]==';') - continue; - if(strnmatch(line, "//", 2)) - continue; - if(!(optname=strtok(line, " \t\r\n"))) { - META_WARNING("'%s' line %d: bad config format: missing option", - loadfile, ln); - continue; - } - if(!(optval=strtok(NULL, "\r\n"))) { - META_WARNING("'%s' line %d: bad config format: missing value", - loadfile, ln); - continue; - } - - if(!(optp=find(optname))) { - META_WARNING("'%s' line %d: unknown option name '%s'", - loadfile, ln, optname); - continue; - } - - if(!set(optp, optval)) { - META_WARNING("'%s' line %d: unable to set option '%s' value '%s'", - loadfile, ln, optname, optval); - continue; - } - } - filename=strdup(loadfile); - fclose(fp); - return(mTRUE); -} - -void DLLINTERNAL MConfig::show(void) { - option_t *optp; - if(filename) - META_CONS("%s and %s:", "Config options from localinfo", filename); - else - META_CONS("%s:", "Config options from localinfo"); - for(optp=list; optp->name; optp++) { - int *optval = (int *) optp->dest; - char **optstr = (char **) optp->dest; - // cvar_t *optcvar = (cvar_t *) optp->dest; - // SETOPT_FN optcmd = (SETOPT_FN) optp->dest; - switch(optp->type) { - case CF_INT: - META_CONS(" %-20s\t%d\n", optp->name, *optval); - break; - case CF_BOOL: - META_CONS(" %-20s\t%s\n", optp->name, - *optval ? "true" : "false"); - break; - case CF_STR: - case CF_PATH: - META_CONS(" %-20s\t%s\n", optp->name, - *optstr ? *optstr : ""); - break; -#if 0 - case CF_CVAR: - META_CONS(" %-20s\tstores in: %s\n", optp->name, optcvar->name); - break; - case CF_CMD: - META_CONS(" %-20s\tparsed by: %d\n", optp->name, (int) optcmd); - break; -#endif - case CF_NONE: - break; - } - } -} diff --git a/src/conf_meta.h b/src/conf_meta.h deleted file mode 100644 index f8fac53..0000000 --- a/src/conf_meta.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CONF_META_H -#define CONF_META_H - -#include "types_meta.h" // mBOOL -#include "new_baseclass.h" -#include "comp_dep.h" - -// Max length of line in config file. -#define MAX_CONF_LEN 1024 - -// Supported config value-types. -typedef enum { - CF_NONE=0, - CF_INT, - CF_BOOL, - CF_STR, - CF_PATH, -#if 0 - CF_CVAR, - CF_CMD, -#endif -} cf_type_t; - -//typedef mBOOL (*SETOPT_FN) (char *key, char *value); - -typedef struct option_s { - char *name; // option name - cf_type_t type; // option type - void *dest; // addr of destination variable, or handler function - char *init; // initial value, as a string, just as config file would -} option_t; - -class MConfig : public class_metamod_new { - private: - // data - option_t *list; - char *filename; - // functions - option_t * DLLINTERNAL find(const char *lookup); - mBOOL DLLINTERNAL set(option_t *setp, const char *value); - // Private; to satisfy -Weffc++ "has pointer data members but does - // not override" copy/assignment constructor. - void operator=(const MConfig &src); - MConfig(const MConfig &src); - public: - // contructor - MConfig(void) DLLINTERNAL; - // data - int debuglevel; // to use for meta_debug - char *gamedll; // string if specified in config.ini - char *plugins_file; // ie metamod.ini, plugins.ini - char *exec_cfg; // ie metaexec.cfg, exec.cfg - int autodetect; // autodetection of gamedll (Metamod-All-Support patch) - int clientmeta; // control 'meta' client-command - // functions - void DLLINTERNAL init(option_t *global_options); - mBOOL DLLINTERNAL load(const char *filename); - mBOOL DLLINTERNAL set(const char *key, const char *value); - void DLLINTERNAL show(void); -}; - -#endif /* CONF_META_H */ diff --git a/src/engine_api.h b/src/engine_api.h deleted file mode 100644 index 470175e..0000000 --- a/src/engine_api.h +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef ENGINE_API_H -#define ENGINE_API_H - -#include "comp_dep.h" - -// Plugin's GetEngineFunctions, called by metamod. -typedef int (*GET_ENGINE_FUNCTIONS_FN) (enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion); - -// According to SDK engine/eiface.h: -//! enginefuncs_t -//! ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 -#define ENGINE_INTERFACE_VERSION 138 - -// Protect against other projects which use this include file but use the -// normal enginefuncs_t type for their meta_engfuncs. -#ifdef __METAMOD_BUILD__ -# include "meta_eiface.h" // meta_enginefuncs_t -extern meta_enginefuncs_t meta_engfuncs DLLHIDDEN; -#else -extern enginefuncs_t meta_engfuncs DLLHIDDEN; -#endif - -// Typedefs for the above functions: - -typedef int (*FN_PRECACHEMODEL) (char* s); -typedef int (*FN_PRECACHESOUND) (char* s); -typedef void (*FN_SETMODEL) (edict_t *e, const char *m); -typedef int (*FN_MODELINDEX) (const char *m); -typedef int (*FN_MODELFRAMES) (int modelIndex); -typedef void (*FN_SETSIZE) (edict_t *e, const float *rgflMin, const float *rgflMax); -typedef void (*FN_CHANGELEVEL) (char *s1, char *s2); -typedef void (*FN_GETSPAWNPARMS) (edict_t *ent); -typedef void (*FN_SAVESPAWNPARMS) (edict_t *ent); -typedef float (*FN_VECTOYAW) (const float *rgflVector); -typedef void (*FN_VECTOANGLES) (const float *rgflVectorIn, float *rgflVectorOut); -typedef void (*FN_MOVETOORIGIN) (edict_t *ent, const float *pflGoal, float dist, int iMoveType); -typedef void (*FN_CHANGEYAW) (edict_t *ent); -typedef void (*FN_CHANGEPITCH) (edict_t *ent); -typedef edict_t * (*FN_FINDENTITYBYSTRING) (edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); -typedef int (*FN_GETENTITYILLUM) (edict_t *pEnt); -typedef edict_t * (*FN_FINDENTITYINSPHERE) (edict_t *pEdictStartSearchAfter, const float *org, float rad); -typedef edict_t * (*FN_FINDCLIENTINPVS) (edict_t *pEdict); -typedef edict_t * (*FN_ENTITIESINPVS) (edict_t *pplayer); -typedef void (*FN_MAKEVECTORS) (const float *rgflVector); -typedef void (*FN_ANGLEVECTORS) (const float *rgflVector, float *forward, float *right, float *up); -typedef edict_t * (*FN_CREATEENTITY) (void); -typedef void (*FN_REMOVEENTITY) (edict_t *e); -typedef edict_t * (*FN_CREATENAMEDENTITY) (int className); -typedef void (*FN_MAKESTATIC) (edict_t *ent); -typedef int (*FN_ENTISONFLOOR) (edict_t *e); -typedef int (*FN_DROPTOFLOOR) (edict_t *e); -typedef int (*FN_WALKMOVE) (edict_t *ent, float yaw, float dist, int iMode); -typedef void (*FN_SETORIGIN) (edict_t *e, const float *rgflOrigin); -typedef void (*FN_EMITSOUND) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch); -typedef void (*FN_EMITAMBIENTSOUND) (edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); -typedef void (*FN_TRACELINE) (const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACETOSS) (edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr); -typedef int (*FN_TRACEMONSTERHULL) (edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACEHULL) (const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_TRACEMODEL) (const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); -typedef const char * (*FN_TRACETEXTURE) (edict_t *pTextureEntity, const float *v1, const float *v2 ); -typedef void (*FN_TRACESPHERE) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); -typedef void (*FN_GETAIMVECTOR) (edict_t *ent, float speed, float *rgflReturn); -typedef void (*FN_SERVERCOMMAND) (char *str); -typedef void (*FN_SERVEREXECUTE) (void); -typedef void (*FN_CLIENTCOMMAND_ENG) (edict_t *pEdict, char *szFmt, ...); -typedef void (*FN_PARTICLEEFFECT) (const float *org, const float *dir, float color, float count); -typedef void (*FN_LIGHTSTYLE) (int style, char *val); -typedef int (*FN_DECALINDEX) (const char *name); -typedef int (*FN_POINTCONTENTS) (const float *rgflVector); -typedef void (*FN_MESSAGEBEGIN) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -typedef void (*FN_MESSAGEEND) (void); -typedef void (*FN_WRITEBYTE) (int iValue); -typedef void (*FN_WRITECHAR) (int iValue); -typedef void (*FN_WRITESHORT) (int iValue); -typedef void (*FN_WRITELONG) (int iValue); -typedef void (*FN_WRITEANGLE) (float flValue); -typedef void (*FN_WRITECOORD) (float flValue); -typedef void (*FN_WRITESTRING) (const char *sz); -typedef void (*FN_WRITEENTITY) (int iValue); -typedef void (*FN_CVARREGISTER) (cvar_t *pCvar); -typedef float (*FN_CVARGETFLOAT) (const char *szVarName); -typedef const char * (*FN_CVARGETSTRING) (const char *szVarName); -typedef void (*FN_CVARSETFLOAT) (const char *szVarName, float flValue); -typedef void (*FN_CVARSETSTRING) (const char *szVarName, const char *szValue); -typedef void (*FN_ALERTMESSAGE) (ALERT_TYPE atype, char *szFmt, ...); -#ifdef HLSDK_3_2_OLD_EIFACE -typedef void (*FN_ENGINEFPRINTF) (FILE *pfile, char *szFmt, ...); -typedef void * (*FN_PVALLOCENTPRIVATEDATA) (edict_t *pEdict, long cb); -#else -typedef void (*FN_ENGINEFPRINTF) (void *pfile, char *szFmt, ...); -typedef void * (*FN_PVALLOCENTPRIVATEDATA) (edict_t *pEdict, int32 cb); -#endif -typedef void * (*FN_PVENTPRIVATEDATA) (edict_t *pEdict); -typedef void (*FN_FREEENTPRIVATEDATA) (edict_t *pEdict); -typedef const char * (*FN_SZFROMINDEX) (int iString); -typedef int (*FN_ALLOCSTRING) (const char *szValue); -typedef struct entvars_s * (*FN_GETVARSOFENT) (edict_t *pEdict); -typedef edict_t * (*FN_PENTITYOFENTOFFSET) (int iEntOffset); -typedef int (*FN_ENTOFFSETOFPENTITY) (const edict_t *pEdict); -typedef int (*FN_INDEXOFEDICT) (const edict_t *pEdict); -typedef edict_t * (*FN_PENTITYOFENTINDEX) (int iEntIndex); -typedef edict_t * (*FN_FINDENTITYBYVARS) (struct entvars_s *pvars); -typedef void * (*FN_GETMODELPTR) (edict_t *pEdict); -typedef int (*FN_REGUSERMSG) (const char *pszName, int iSize); -typedef void (*FN_ANIMATIONAUTOMOVE) (const edict_t *pEdict, float flTime); -typedef void (*FN_GETBONEPOSITION) (const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); -#ifdef HLSDK_3_2_OLD_EIFACE -typedef unsigned long (*FN_FUNCTIONFROMNAME) ( const char *pName ); -typedef const char * (*FN_NAMEFORFUNCTION) ( unsigned long function ); -#else -typedef uint32 (*FN_FUNCTIONFROMNAME) ( const char *pName ); -typedef const char * (*FN_NAMEFORFUNCTION) ( uint32 function ); -#endif -typedef void (*FN_CLIENTPRINTF) ( edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg ); -typedef void (*FN_SERVERPRINT) ( const char *szMsg ); -typedef const char * (*FN_CMD_ARGS) ( void ); -typedef const char * (*FN_CMD_ARGV) ( int argc ); -typedef int (*FN_CMD_ARGC) ( void ); -typedef void (*FN_GETATTACHMENT) (const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); -typedef void (*FN_CRC32_INIT) (CRC32_t *pulCRC); -typedef void (*FN_CRC32_PROCESSBUFFER) (CRC32_t *pulCRC, void *p, int len); -typedef void (*FN_CRC32_PROCESSBYTE) (CRC32_t *pulCRC, unsigned char ch); -typedef CRC32_t (*FN_CRC32_FINAL) (CRC32_t pulCRC); -#ifdef HLSDK_3_2_OLD_EIFACE -typedef long (*FN_RANDOMLONG) (long lLow, long lHigh); -#else -typedef int32 (*FN_RANDOMLONG) (int32 lLow, int32 lHigh); -#endif -typedef float (*FN_RANDOMFLOAT) (float flLow, float flHigh); -typedef void (*FN_SETVIEW) (const edict_t *pClient, const edict_t *pViewent ); -typedef float (*FN_TIME) ( void ); -typedef void (*FN_CROSSHAIRANGLE) (const edict_t *pClient, float pitch, float yaw); -typedef byte * (*FN_LOADFILEFORME) (char *filename, int *pLength); -typedef void (*FN_FREEFILE) (void *buffer); -typedef void (*FN_ENDSECTION) (const char *pszSectionName); -typedef int (*FN_COMPAREFILETIME) (char *filename1, char *filename2, int *iCompare); -typedef void (*FN_GETGAMEDIR) (char *szGetGameDir); -typedef void (*FN_CVAR_REGISTERVARIABLE) (cvar_t *variable); -typedef void (*FN_FADECLIENTVOLUME) (const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); -typedef void (*FN_SETCLIENTMAXSPEED) (const edict_t *pEdict, float fNewMaxspeed); -typedef edict_t * (*FN_CREATEFAKECLIENT) (const char *netname); -typedef void (*FN_RUNPLAYERMOVE) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); -typedef int (*FN_NUMBEROFENTITIES) (void); -typedef char * (*FN_GETINFOKEYBUFFER) (edict_t *e); -typedef char * (*FN_INFOKEYVALUE) (char *infobuffer, char *key); -typedef void (*FN_SETKEYVALUE) (char *infobuffer, char *key, char *value); -typedef void (*FN_SETCLIENTKEYVALUE) (int clientIndex, char *infobuffer, char *key, char *value); -typedef int (*FN_ISMAPVALID) (char *filename); -typedef void (*FN_STATICDECAL) ( const float *origin, int decalIndex, int entityIndex, int modelIndex ); -typedef int (*FN_PRECACHEGENERIC) (char *s); -typedef int (*FN_GETPLAYERUSERID) (edict_t *e ); -typedef void (*FN_BUILDSOUNDMSG) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); -typedef int (*FN_ISDEDICATEDSERVER) (void); -typedef cvar_t * (*FN_CVARGETPOINTER) (const char *szVarName); -typedef unsigned int (*FN_GETPLAYERWONID) (edict_t *e); -typedef void (*FN_INFO_REMOVEKEY) ( char *s, const char *key ); -typedef const char * (*FN_GETPHYSICSKEYVALUE) ( const edict_t *pClient, const char *key ); -typedef void (*FN_SETPHYSICSKEYVALUE) ( const edict_t *pClient, const char *key, const char *value ); -typedef const char * (*FN_GETPHYSICSINFOSTRING) ( const edict_t *pClient ); -typedef unsigned short (*FN_PRECACHEEVENT) ( int type, const char *psz ); -typedef void (*FN_PLAYBACKEVENT) ( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); -typedef unsigned char * (*FN_SETFATPVS) ( float *org ); -typedef unsigned char * (*FN_SETFATPAS) ( float *org ); -typedef int (*FN_CHECKVISIBILITY) ( const edict_t *entity, unsigned char *pset ); -typedef void (*FN_DELTASETFIELD) ( struct delta_s *pFields, const char *fieldname ); -typedef void (*FN_DELTAUNSETFIELD) ( struct delta_s *pFields, const char *fieldname ); -typedef void (*FN_DELTAADDENCODER) ( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); -typedef int (*FN_GETCURRENTPLAYER) ( void ); -typedef int (*FN_CANSKIPPLAYER) ( const edict_t *player ); -typedef int (*FN_DELTAFINDFIELD) ( struct delta_s *pFields, const char *fieldname ); -typedef void (*FN_DELTASETFIELDBYINDEX) ( struct delta_s *pFields, int fieldNumber ); -typedef void (*FN_DELTAUNSETFIELDBYINDEX) ( struct delta_s *pFields, int fieldNumber ); -typedef void (*FN_SETGROUPMASK) ( int mask, int op ); -typedef int (*FN_CREATEINSTANCEDBASELINE) ( int classname, struct entity_state_s *baseline ); -typedef void (*FN_CVAR_DIRECTSET) ( struct cvar_s *var, char *value ); -typedef void (*FN_FORCEUNMODIFIED) ( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); -typedef void (*FN_GETPLAYERSTATS) ( const edict_t *pClient, int *ping, int *packet_loss ); -typedef void (*FN_ADDSERVERCOMMAND) ( char *cmd_name, void (*function) (void) ); -// Added in SDK 2.2: -typedef qboolean (*FN_VOICE_GETCLIENTLISTENING) (int iReceiver, int iSender); -typedef qboolean (*FN_VOICE_SETCLIENTLISTENING) (int iReceiver, int iSender, qboolean bListen); -// Added for HL 1109 (no SDK update): -typedef const char * (*FN_GETPLAYERAUTHID) (edict_t *e); -// Added 2003/11/10 (no SDK update): -typedef sequenceEntry_s * (*FN_SEQUENCEGET) (const char* fileName, const char* entryName); -typedef sentenceEntry_s * (*FN_SEQUENCEPICKSENTENCE) (const char* groupName, int pickMethod, int *picked); -typedef int (*FN_GETFILESIZE) (char *filename); -typedef unsigned int (*FN_GETAPPROXWAVEPLAYLEN) (const char *filepath); -typedef int (*FN_ISCAREERMATCH) (void); -typedef int (*FN_GETLOCALIZEDSTRINGLENGTH) (const char *label); -typedef void (*FN_REGISTERTUTORMESSAGESHOWN) (int mid); -typedef int (*FN_GETTIMESTUTORMESSAGESHOWN) (int mid); -typedef void (*FN_PROCESSTUTORMESSAGEDECAYBUFFER) (int *buffer, int bufferLength); -typedef void (*FN_CONSTRUCTTUTORMESSAGEDECAYBUFFER) (int *buffer, int bufferLength); -typedef void (*FN_RESETTUTORMESSAGEDECAYDATA) (void); -// Added 2005/08/11 (no SDK update): -typedef void (*FN_QUERYCLIENTCVARVALUE) ( const edict_t *player, const char *cvarName ); -// Added 2005/11/21 (no SDK update): -typedef void (*FN_QUERYCLIENTCVARVALUE2) ( const edict_t *player, const char *cvarName, int requestID ); -// Added 2009/06/17 (no SDK update): -typedef void (*FN_ENGCHECKPARM) ( const char *pchCmdLineToken, char **pchNextVal ); - -#endif /* ENGINE_API_H */ diff --git a/src/engine_t.h b/src/engine_t.h deleted file mode 100644 index f3ff86b..0000000 --- a/src/engine_t.h +++ /dev/null @@ -1,82 +0,0 @@ -// vi: set ts=4 sw=4 : -// vim: set tw=75 : - -// engine_t.h - The engine_t type - -/* - * Copyright (c) 2001-2006 Will Day - * - * This file is part of Metamod. - * - * Metamod is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Metamod is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Metamod; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, the author gives permission to - * link the code of this program with the Half-Life Game Engine ("HL - * Engine") and Modified Game Libraries ("MODs") developed by Valve, - * L.L.C ("Valve"). You must obey the GNU General Public License in all - * respects for all of the code used other than the HL Engine and MODs - * from Valve. If you modify this file, you may extend this exception - * to your version of the file, but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. - * - */ - -#ifndef MM_ENGINE_T_H -#define MM_ENGINE_T_H - -#include "eiface.h" // engfuncs_t, globalvars_t -#include "engineinfo.h" // EngineInfo -#include "comp_dep.h" -#include "osdep.h" //unlikely, OPEN_ARGS - -// Our structure for storing engine references. -struct engine_t { - engine_t() DLLINTERNAL; - engine_t(const engine_t&) DLLINTERNAL; - engine_t& operator=(const engine_t&) DLLINTERNAL; - - enginefuncs_t *funcs; // engine funcs - globalvars_t *globals; // engine globals - enginefuncs_t *pl_funcs; // "modified" eng funcs we give to plugins - EngineInfo info; // some special info elements -}; - -inline engine_t::engine_t() - : funcs(NULL), globals(NULL), pl_funcs(NULL), info() -{ -} - - -inline engine_t::engine_t(const engine_t& _rhs) - : funcs(_rhs.funcs), globals(_rhs.globals), pl_funcs(_rhs.pl_funcs), info(_rhs.info) -{ -} - - -inline engine_t& engine_t::operator=(const engine_t& _rhs) -{ - funcs = _rhs.funcs; - globals = _rhs.globals; - pl_funcs = _rhs.pl_funcs; - info = _rhs.info; - return *this; -} - - -extern engine_t Engine DLLHIDDEN; - -#endif /* MM_ENGINE_T_H */ - diff --git a/src/engineinfo.cpp b/src/engineinfo.cpp deleted file mode 100644 index bb7fd37..0000000 --- a/src/engineinfo.cpp +++ /dev/null @@ -1,379 +0,0 @@ -#ifdef _WIN32 - // Don't include winspool.h; clashes with SERVER_EXECUTE from engine -# define _WINSPOOL_H -# include -# include // Header structures -#else -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -# include // dladdr() -# include // ElfW(Phdr/Ehdr) macros. - // _DYNAMIC, r_debug, link_map, etc. -#endif /* _WIN32 */ - -#include // strlen(), strrchr(), strcmp() -#include // printf() - -#include "engineinfo.h" // me -#include "log_meta.h" // META_DEV() - - -// Current mask for checking engine function addresses -// in VAC protected engine dlls on Win32. This is gonna fail -// on Win64. -const unsigned long c_VacDllEngineFuncsRangeMask = 0xFFF00000; -const unsigned long c_VacDllEngineFuncsRangeMark = 0x01D00000; -void* const c_VacDllEngineFuncsRangeStart = (void*)0x01D00000; -void* const c_VacDllEngineFuncsRangeEnd = (void*)0x01E00000; - - -bool DLLINTERNAL EngineInfo::check_for_engine_module( const char* _pName ) -{ - const char* pC; - size_t size; - - if ( NULL == _pName ) return false; - -#ifdef _WIN32 - - // The engine module is either sw.dll or hw.dll or swds.dll - pC = Q_strrchr( _pName, '.' ); - - pC -= 2; - if ( 0 != Q_strcmp(pC, "sw.dll") && 0 != Q_strcmp(pC, "hw.dll") ) { - pC -= 2; - if ( 0 != Q_strcmp(pC, "swds.dll") ) return false; - } - - HMODULE hModule = GetModuleHandle( pC ); - if ( NULL == hModule ) { - return false; - } - - // Ok, we found the string sw(ds).dll, thus we deduct that this is the - // name of the engine's shared object. We copy the string for future - // reference and return successfully. - size = 0; - while ( *pC != '.' && size < c_EngineInfo__typeLen-1 ) { - m_type[size++] = *pC++; - } - m_type[size] = '\0'; - -#else /* _WIN32 */ - - const char* pType; - - - size = Q_strlen( _pName ); - if ( size < 11 ) { - // Forget it, this string is too short to even be 'engine_.so', so - // it can't the name of the engine shared library. - return false; - } - - // Start parsing at the end. Since we know that the string is at least - // 11 characters long we can safely do our parsing without being afraid - // of leaving the string. - pC = _pName + size -1; - - // First we see if the string ends in '.so' - if ( *pC-- != 'o' || *pC-- != 's' || *pC-- != '.' ) return false; - - // Now find the '_' which would be the seperator between 'engine' and - // the architecture. - while ( *pC != '_' && pC != _pName ) --pC; - if ( pC == _pName ) return false; - - // We are at the '_', thus the architecture identifier must start at - // the next character. - pType = pC +1; - - // Now we walk further back and check if we find the string 'engine' - // backwards. - --pC; - if ( *pC-- != 'e' || *pC-- != 'n' || *pC-- != 'i' || - *pC-- != 'g' || *pC-- != 'n' || *pC != 'e' ) { - return false; - } - - // Ok, we found the string engine_*.so, thus we deduct that this is the - // name of the engine's shared object. We copy the architecture string - // for future reference and return successfully. - size = 0; - while ( *pType != '.' && size < c_EngineInfo__typeLen-1 ) { - m_type[size++] = *pType++; - } - m_type[size] = '\0'; - - -#endif /* _WIN32 */ - - - return true; -} - - -#ifdef _WIN32 - -int DLLINTERNAL EngineInfo::nthdr_module_name( void ) -{ - PIMAGE_DOS_HEADER pDosHeader; - PIMAGE_NT_HEADERS pNTHeader; - unsigned char* pBaseAddr; - const char* pName = "sw.dll"; - - if ( ! check_for_engine_module(pName) ) { - pName = "hw.dll"; - if ( ! check_for_engine_module(pName) ) { - pName = "swds.dll"; - if ( ! check_for_engine_module(pName) ) { - return MODULE_NAME_NOTFOUND; - } - } - } - - // Get the module handle for the engine dll we found. - // This is also the modules base address. - HMODULE hModule = GetModuleHandle( pName ); - - pBaseAddr = (unsigned char*)hModule; - - - // Check if we find a DOS header - pDosHeader = (PIMAGE_DOS_HEADER)hModule; - if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) { - return INVALID_DOS_SIGN; - } - - // Check if we find a PE header - pNTHeader = (PIMAGE_NT_HEADERS)(pBaseAddr + pDosHeader->e_lfanew); - if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE ) { - return INVALID_NT_SIGN; - } - - set_code_range( pBaseAddr, pNTHeader ); - return 0; -} - - -int DLLINTERNAL EngineInfo::vac_pe_approx( enginefuncs_t* _pFuncs ) -{ - if ( NULL == _pFuncs ) return INVALID_ARG; - - // There is really no good and easy way to do this. Right now what - // we do is assume that Steam listenservers will normally be - // up-to-date and hence have all function pointers set correctly. - // So we just check for some anomality and then set some approximated - // values. - - // The known addresses at the time of writing all start with 0x01D and - // this lie in the range between 0x01D00000 and 0x01E00000. What we do - // is check all functions pointers that are known to be good to start - // with 0x01D. If that is the case then we know that the loading address - // of the engine functions hasn't changed and we assume the above stated - // range to be the range of valid engine function addresses. - // If we find functions outside this range we can't determine a valid - // range and have to just give up. - - unsigned long* pengfuncs = (unsigned long*)_pFuncs; - unsigned int i, invals = 0; - for ( i = 0, pengfuncs += i; i < 140; i++, pengfuncs++ ) { - if ( ((*pengfuncs) & c_VacDllEngineFuncsRangeMask) != c_VacDllEngineFuncsRangeMark ) { - invals++; - break; - } - } - - if ( invals > 0 ) { - META_DEV( "Found %d engine functions out of range 0x%08lx. " - "Unable to determine valid engine code address range.", - invals, c_VacDllEngineFuncsRangeMark ); - - Q_strncpy( m_type, "vacdll+?", c_EngineInfo__typeLen ); - m_state = STATE_INVALID; - return STATE_INVALID; - } - - m_codeStart = c_VacDllEngineFuncsRangeStart; - m_codeEnd = c_VacDllEngineFuncsRangeEnd; - - Q_strncpy( m_type, "vacdll", c_EngineInfo__typeLen ); - - m_state = STATE_VALID; - - return 0; -} - - -void DLLINTERNAL EngineInfo::set_code_range( unsigned char* _pBase, PIMAGE_NT_HEADERS _pNThdr ) -{ - m_codeStart = _pBase + _pNThdr->OptionalHeader.BaseOfCode; - m_codeEnd = _pBase + _pNThdr->OptionalHeader.BaseOfCode + _pNThdr->OptionalHeader.SizeOfCode; - - m_state = STATE_VALID; -} - - -#else /* _WIN32 */ - - -int DLLINTERNAL EngineInfo::phdr_elfhdr( void* _pElfHdr ) -{ - ElfW(Ehdr)* pEhdr = (ElfW(Ehdr)*)_pElfHdr; - ElfW(Phdr)* pPhdr; - - if ( NULL == _pElfHdr ) return INVALID_ARG; - - if ( pEhdr->e_ident[0] == 0x7f - && pEhdr->e_ident[1] == 'E' - && pEhdr->e_ident[2] == 'L' - && pEhdr->e_ident[3] == 'F' ) { - - // Looking good, we found an ELF signature. - // Let's see if the rest of the data at this address would fit an ELH header, too. - if ( (pEhdr->e_ident[EI_CLASS] == ELFCLASS32 //ELFW(CLASS) - || pEhdr->e_ident[EI_CLASS] == ELFCLASS64) - - && (pEhdr->e_ident[EI_DATA] == ELFDATA2LSB - || pEhdr->e_ident[EI_DATA] == ELFDATA2MSB) - - && pEhdr->e_type == ET_DYN ) { - - // Ok, we believe that this is a shared object's ELF header. - // Let's find the program header for the segment that includes - // the text section and return it. - - pPhdr = (ElfW(Phdr) *) ((char *) pEhdr + pEhdr->e_phoff); - for ( int i = 0; i < pEhdr->e_phnum; i++, pPhdr++ ) { - - if ( PT_LOAD == pPhdr->p_type - && (pPhdr->p_flags & PF_R) - && (pPhdr->p_flags & PF_X) ) { - - // The text section gets loaded and has read and - // execute flags set. So this must be it. - set_code_range( pEhdr, pPhdr ); - return 0; - } - } - } - } - - return HEADER_NOTFOUND; -} - - - - -int DLLINTERNAL EngineInfo::phdr_dladdr( void* _pMem ) -{ - Dl_info info; - - if ( 0 != dladdr(_pMem, &info) ) { - // Check if this is the engine module - if ( check_for_engine_module(info.dli_fname) ) { - return phdr_elfhdr( info.dli_fbase ); - } - } - - return NOTFOUND; -} - - -int DLLINTERNAL EngineInfo::phdr_r_debug( void ) -{ - ElfW(Dyn)* pDyn; - struct r_debug* pr_debug; - struct link_map* pMap; - - - // Search if we have a DT_DEBUG symbol in our DYNAMIC segment, which - // ought to be set to the r_debug structure's address. - for (pDyn = _DYNAMIC; pDyn->d_tag != DT_NULL; ++pDyn) { - if (pDyn->d_tag == DT_DEBUG) { - pr_debug = (struct r_debug *) pDyn->d_un.d_ptr; - break; - } - } - - if ( DT_NULL == pDyn->d_tag ) { - } - else if ( NULL == pr_debug ) { - } - else { - pMap = pr_debug->r_map; - - // Walk to the start of the list - while ( pMap->l_prev != NULL ) pMap = pMap->l_prev; - do { - if ( check_for_engine_module(pMap->l_name) ) { - return phdr_elfhdr( (void*)pMap->l_addr ); - } - - pMap = pMap->l_next; - } while ( NULL != pMap ); - - } - - return NOTFOUND; -} - -void DLLINTERNAL EngineInfo::set_code_range( void* _pBase, ElfW(Phdr)* _pPhdr ) -{ - unsigned char* pBase = (unsigned char*)_pBase; - m_codeStart = pBase + _pPhdr->p_vaddr; - m_codeEnd = pBase + _pPhdr->p_vaddr + _pPhdr->p_memsz; - - m_state = STATE_VALID; -} - - -#endif /* _WIN32 */ - - -int DLLINTERNAL EngineInfo::initialise( enginefuncs_t* _pFuncs ) -{ - int ret = 0; - - // Have to do this only once. - if ( NULL != m_codeStart ) { - return 0; - } - -#ifdef _WIN32 - - ret = nthdr_module_name(); - if ( MODULE_NAME_NOTFOUND == ret && (! _pFuncs->pfnIsDedicatedServer()) ) { - // We could not find the engine dll by name and we are running on - // a listen server. This usually means that that we are dealing with - // a VAC protected engine dll. No other way than approximating the - // range of valid engine function pointers in this case. - ret = vac_pe_approx( _pFuncs ); - } - -#else /* _WIN32 */ - - // If we have no reference pointer to start from we can only try to use - // the r_debug symbol. - if ( NULL == _pFuncs ) { - ret = phdr_r_debug(); - } - - // If we have a refererence pointer we try to use it first. - if ( 0 != phdr_dladdr(_pFuncs) ) { - ret = phdr_r_debug(); - } - -#endif /* _WIN32 */ - - if ( 0 != ret ) { - META_DEV( "Unable to determine engine code address range!" ); - } - else { - META_DEV( "Set engine code range: start address = %p, end address = %p", - m_codeStart, m_codeEnd ); - } - - return 0; -} diff --git a/src/engineinfo.h b/src/engineinfo.h deleted file mode 100644 index 355745b..0000000 --- a/src/engineinfo.h +++ /dev/null @@ -1,245 +0,0 @@ -#ifndef MM_ENGINEINFO_H -#define MM_ENGINEINFO_H - -#ifdef _WIN32 -typedef void* MemAddr; -#else -# include // ElfW(Addr/Phdr) macros -typedef void* MemAddr; -#endif /* _WIN32 */ - -#include "extdll.h" // eiface.h: enginefuncs_t - -#include "comp_dep.h" -#include "osdep.h" //unlikely, OPEN_ARGS -#include "new_baseclass.h" - -// What we return in is_valid_code_pointer() when the EngineInfo object is -// in an INVALID state, i.e. no code address range could be determined. -static const bool c_DefaultReturnOnInvalidState = true; - -static const int c_EngineInfo__typeLen = 10; - -class EngineInfo : public class_metamod_new -{ - private: - // data : - MemAddr m_codeStart; - MemAddr m_codeEnd; - // State is either NULL when not yet initialised, - // VALID if a code range could be determined - // or INVALID when no valid range for code addresses - // could be determined. - char m_state; - - // Type of engine dso/dll used. - // For Linux this specifies the architecture, i.e. 'i486', 'i686', - // 'amd', 'amd64' etc. - // For Windows this is either 'sw' or 'hw' or 'swds' depending on - // the server type. - char m_type[c_EngineInfo__typeLen]; - - // functions : - - // Check if string is valid name of engine dso/dll. - bool DLLINTERNAL check_for_engine_module( const char* pName ); - -#ifdef _WIN32 - - // Set info using the PE header found by module name. - // Returns 0 on success, error code on failure. - int DLLINTERNAL nthdr_module_name( void ); - - int DLLINTERNAL vac_pe_approx( enginefuncs_t* pFuncs ); - - // Set code segment start and end from PEheader. The base - // address, that relative addresses are based on, is passed in - // pBase. - void DLLINTERNAL set_code_range( unsigned char* pBase, PIMAGE_NT_HEADERS pNThdr ); - -#else - - // Set info using the Programheader found via r_debug struct. - // Returns 0 on success, error code on failure. - int DLLINTERNAL phdr_r_debug( void ); - // Set info using the Programheader found with reference address - // via dladdr(). Returns 0 on success, error code on failure. - int DLLINTERNAL phdr_dladdr( void* pMem ); - // Set info using the Programheader found via ELF header passed as - // pElfHdr. Return 0 on success, error code on failure. - int DLLINTERNAL phdr_elfhdr( void* pElfHdr ); - // Set code segment start and end from Programheader. The base - // address, that relative addresses are based on, is passed in - // pBase. - void DLLINTERNAL set_code_range( void* pBase, ElfW(Phdr)* pPhdr ); - -#endif /* _WIN32 */ - - public: - // codes : - - enum { - STATE_NULL = 0, - STATE_VALID, - STATE_INVALID, - - MODULE_NAME_NOTFOUND = 5, - INVALID_DOS_SIGN, - INVALID_NT_SIGN, - INVALID_ARG, - HEADER_NOTFOUND, - NOTFOUND - }; - - - // functions : - - EngineInfo() DLLINTERNAL; - EngineInfo& operator=( const EngineInfo& ) DLLINTERNAL; - EngineInfo( const EngineInfo& ) DLLINTERNAL; - - const char* DLLINTERNAL type( void ); - - // Initilaise object, determining the bounds of the code segment of - // the HL engine shared object. - int DLLINTERNAL initialise( enginefuncs_t* pFuncs = NULL ); - - // Test if pMem is within bounds of the code segment. - bool DLLINTERNAL is_valid_code_pointer( void* pMem ); - - // Overloaded versions of above test to keep the ugly pointer - // conversion stuff in here. - bool DLLINTERNAL is_valid_code_pointer( const char* (*fp) (edict_t*) ); - bool DLLINTERNAL is_valid_code_pointer( sequenceEntry_s* (*fp) (const char*, const char*) ); - bool DLLINTERNAL is_valid_code_pointer( sentenceEntry_s* (*fp) (const char*, int, int*) ); - bool DLLINTERNAL is_valid_code_pointer( int (*fp) (char*) ); - bool DLLINTERNAL is_valid_code_pointer( unsigned int (*fp) (const char*) ); - bool DLLINTERNAL is_valid_code_pointer( int (*fp) (void) ); - bool DLLINTERNAL is_valid_code_pointer( int (*fp) (const char*) ); - bool DLLINTERNAL is_valid_code_pointer( void (*fp) (int) ); - bool DLLINTERNAL is_valid_code_pointer( int (*fp) (int) ); - bool DLLINTERNAL is_valid_code_pointer( void (*fp) (int*, int) ); - bool DLLINTERNAL is_valid_code_pointer( void (*fp) (void) ); - bool DLLINTERNAL is_valid_code_pointer( void (*fp) (const edict_t*, const char*) ); - bool DLLINTERNAL is_valid_code_pointer( void (*fp) (const edict_t*, const char*, int) ); - bool DLLINTERNAL is_valid_code_pointer( int (*fp) (const char *, char**) ); -}; - -// We probably should run an initialisation here without a reference -// pointer so that the object has valid info in any case. -inline EngineInfo::EngineInfo() : - m_codeStart(NULL), - m_codeEnd(NULL), - m_state(STATE_NULL) -{ - m_type[0] = '\0'; -} - - -inline EngineInfo::EngineInfo( const EngineInfo& _rhs) : - m_codeStart(_rhs.m_codeStart), - m_codeEnd(_rhs.m_codeEnd), - m_state(STATE_NULL) -{ - Q_memcpy( m_type, _rhs.m_type, c_EngineInfo__typeLen ); -} - - -inline EngineInfo& EngineInfo::operator=( const EngineInfo& _rhs) -{ - m_state = _rhs.m_state; - m_codeStart = _rhs.m_codeStart; - m_codeEnd = _rhs.m_codeEnd; - Q_memcpy( m_type, _rhs.m_type, c_EngineInfo__typeLen ); - return *this; -} - -inline const char* EngineInfo::type( void ) -{ - return m_type; -} - -inline bool EngineInfo::is_valid_code_pointer( void* _pMem ) -{ - if ( STATE_INVALID == m_state ) - { - return c_DefaultReturnOnInvalidState; - } - if ( NULL != _pMem && m_codeStart <= _pMem && _pMem <= m_codeEnd ) - { - return true; - } - return false; -} - -inline bool EngineInfo::is_valid_code_pointer( const char* (*_fp) (edict_t*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( sequenceEntry_s* (*_fp) (const char*, const char*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( sentenceEntry_s* (*_fp) (const char*, int, int*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (char*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( unsigned int (*_fp) (const char*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (void) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (const char*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (int) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (int) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (int*, int) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (void) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (const edict_t*, const char*) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( void (*_fp) (const edict_t*, const char*, int) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -inline bool EngineInfo::is_valid_code_pointer( int (*_fp) (const char*, char**) ) -{ - return is_valid_code_pointer( (void*)_fp ); -} - -#endif /* MM_ENGINEINFO_H */ diff --git a/src/game_autodetect.cpp b/src/game_autodetect.cpp deleted file mode 100644 index 9b03f42..0000000 --- a/src/game_autodetect.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include // always -#include "osdep_p.h" // is_gamedll, ... -#include "game_autodetect.h" // me -#include "support_meta.h" // full_gamedir_path, - - -// Search gamedir/dlls/*.dll for gamedlls -//TODO: add META_DEBUG -const char * DLLINTERNAL autodetect_gamedll(const gamedll_t *gamedll, const char *knownfn) -{ - static char buf[256]; - char dllpath[256]; - char fnpath[256]; - DIR *dir; - struct dirent *ent; - unsigned int fn_len; - // Generate dllpath - safevoid_snprintf(buf, sizeof(buf), "%s/dlls", gamedll->gamedir); - if(!full_gamedir_path(buf, dllpath)) { - //whine & return - META_WARNING("GameDLL-Autodetection: Directory '%s' doesn't exist.", buf); - return(0); - } - // Generate knownfn path - safevoid_snprintf(fnpath, sizeof(fnpath), "%s/%s", dllpath, knownfn); - // Check if knownfn exists and is valid gamedll - if(is_gamedll(fnpath)) - { - // knownfn exists and is loadable gamedll, return 0. - return(0); - } - // Open directory - if(!(dir = opendir(dllpath))) - { - //whine & return - META_WARNING("GameDLL-Autodetection: Couldn't open directory '%s'.", dllpath); - return(0); - } - while((ent = readdir(dir)) != 0) - { - fn_len = Q_strlen(ent->d_name); - if(fn_len <= Q_strlen(PLATFORM_DLEXT)) - { - // Filename is too short - continue; - } - // Compare end of filename with PLATFORM_DLEXT - if(!strcasematch(&ent->d_name[fn_len - Q_strlen(PLATFORM_DLEXT)], PLATFORM_DLEXT)) - { - // File isn't dll - continue; - } - // Exclude all metamods - if(strncasematch(ent->d_name, "metamod", Q_strlen("metamod"))) - { - continue; - } - // Exclude all bots - STRNCPY(buf, ent->d_name, sizeof(buf)); - strlwr(buf); - if(Q_strstr(buf, "bot.")) - { - continue; - } -#ifdef linux - //bot_iX86.so, bot_amd64.so, bot_x86_64.so - if(Q_strstr(buf, "bot_i") || Q_strstr(buf, "bot_amd64.so") || Q_strstr(buf, "bot_x86")) - { - continue; - } -#endif - // Generate full path - safevoid_snprintf(fnpath, sizeof(fnpath), "%s/%s", dllpath, ent->d_name); - // Check if dll is gamedll - if(is_gamedll(fnpath)) - { - META_DEBUG(8, ("is_gamedll(%s): ok.", fnpath)); - //gamedll detected - STRNCPY(buf, ent->d_name, sizeof(buf)); - closedir(dir); - return(buf); - } - META_DEBUG(8, ("is_gamedll(%s): failed.", fnpath)); - } - //not found - META_WARNING("GameDLL-Autodetection: Couldn't find gamedll in '%s'.", dllpath); - closedir(dir); - return(0); -} diff --git a/src/game_autodetect.h b/src/game_autodetect.h deleted file mode 100644 index 199ab69..0000000 --- a/src/game_autodetect.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef GAME_AUTODETECT_H -#define GAME_AUTODETECT_H - -#include "metamod.h" -const char * DLLINTERNAL autodetect_gamedll(const gamedll_t *gamedll, const char *knownfn); - -#endif /*GAME_AUTODETECT_H*/ diff --git a/src/game_support.cpp b/src/game_support.cpp deleted file mode 100644 index 07cae68..0000000 --- a/src/game_support.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include // open, write -#include // always -#include "game_support.h" // me -#include "log_meta.h" // META_LOG, etc -#include "types_meta.h" // mBOOL -#include "osdep.h" // win32 snprintf, etc -#include "game_autodetect.h" // autodetect_gamedll -#include "support_meta.h" // MIN - -// Adapted from adminmod h_export.cpp: -//! this structure contains a list of supported mods and their dlls names -//! To add support for another mod add an entry here, and add all the -//! exported entities to link_func.cpp -const game_modlist_t known_games = { - // name/gamedir linux_so win_dll desc - // - // Previously enumerated in this sourcefile, the list is now kept in a - // separate file, generated based on game information stored in a - // convenient db. - // -#include "games.h" - // End of list terminator: - {NULL, NULL, NULL, NULL} -}; - -// Find a modinfo corresponding to the given game name. -const game_modinfo_t * DLLINTERNAL lookup_game(const char *name) { - const game_modinfo_t *imod; - int i; - for(i=0; known_games[i].name; i++) { - imod=&known_games[i]; - if(strcasematch(imod->name, name)) - return(imod); - } - // no match found - return(NULL); -} - -// Installs gamedll from Steam cache -mBOOL DLLINTERNAL install_gamedll(char *from, const char *to) { - int length_in; - int length_out; - - if(!from) - return mFALSE; - if(!to) - to = from; - - byte* cachefile = LOAD_FILE_FOR_ME(from, &length_in); - - // If the file seems to exist in the cache. - if(cachefile) { - int fd=open(to, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); - - if(fd < 0) { - META_DEBUG(3, ("Installing gamedll from cache: Failed to create file %s: %s", to, strerror(errno)) ); - FREE_FILE(cachefile); - return(mFALSE); - } - - length_out=write(fd, cachefile, length_in); - FREE_FILE(cachefile); - close(fd); - - // Writing the file was not successfull - if(length_out != length_in) { - META_DEBUG(3,("Installing gamedll from chache: Failed to write all %d bytes to file, only %d written: %s", length_in, length_out, strerror(errno))); - // Let's not leave a mess but clean up nicely. - if(length_out >= 0) - unlink(to); - - return(mFALSE); - } - - META_LOG("Installed gamedll %s from cache.", to); - } else { - META_DEBUG(3, ("Failed to install gamedll from cache: file %s not found in cache.", from) ); - return(mFALSE); - } - - return(mTRUE); -} - -// Set all the fields in the gamedll struct, - based either on an entry in -// known_games matching the current gamedir, or on one specified manually -// by the server admin. -// -// meta_errno values: -// - ME_NOTFOUND couldn't recognize game -mBOOL DLLINTERNAL setup_gamedll(gamedll_t *gamedll) { -#ifdef __x86_64__ - static char fixname_amd64[NAME_MAX]; // pointer is given outside function -#endif - static char override_desc_buf[NAME_MAX]; // pointer is given outside function - static char autodetect_desc_buf[NAME_MAX]; // pointer is given outside function - char install_path[NAME_MAX]; - const game_modinfo_t *known; - char *cp; - const char *autofn = 0, *knownfn=0, *usedfn = 0; - int override=0; - - // Check for old-style "metagame.ini" file and complain. - if(valid_gamedir_file(OLD_GAMEDLL_TXT)) - META_WARNING("File '%s' is no longer supported; instead, specify override gamedll in %s or with '+localinfo mm_gamedll '", OLD_GAMEDLL_TXT, CONFIG_INI); - // First, look for a known game, based on gamedir. - if((known=lookup_game(gamedll->name))) { -#ifdef _WIN32 - knownfn=known->win_dll; -#elif defined(linux) - knownfn=known->linux_so; - #ifdef __x86_64__ - //AMD64: convert _i386.so to _amd64.so - if((cp = Q_strstr(knownfn, "_i386.so")) || - (cp = Q_strstr(knownfn, "_i486.so")) || - (cp = Q_strstr(knownfn, "_i586.so")) || - (cp = Q_strstr(knownfn, "_i686.so"))) { - //make sure that it's the ending that has "_iX86.so" - if(cp[Q_strlen("_i386.so")] == 0) { - STRNCPY(fixname_amd64, known->linux_so, - MIN(((size_t)cp - (size_t)knownfn) + 1, - sizeof(fixname_amd64))); - strncat(fixname_amd64, "_amd64.so", sizeof(fixname_amd64)); - - knownfn=fixname_amd64; - } - } - #endif /*__x86_64__*/ -#else -#error "OS unrecognized" -#endif /* _WIN32 */ - - // Do this before autodetecting gamedll from "dlls/*.dll" - if(!Config->gamedll) { -#ifdef linux - // The engine changed game dll lookup behaviour in that it strips - // anything after the last '_' from the name and tries to load the - // resulting name. The DSO names were changed and do not have the - // '_i386' part in them anymore, so cs_i386.so became cs.so. We - // have to adapt to that and try to load the DSO name without the - // '_*' part first, to see if we have a new version file available. - char temp_str[NAME_MAX], *strippedfn; - - STRNCPY(temp_str, knownfn, sizeof(temp_str)); - strippedfn = temp_str; - - char *loc = Q_strrchr(strippedfn, '_'); - - // A small safety net here: make sure that we are dealing with - // a file name at least four characters long and ending in - // '.so'. This way we can be sure that we can safely overwrite - // anything from the '_' on with '.so'. - int size = 0; - const char *ext; - if(0 != loc) { - size = Q_strlen(strippedfn); - ext = strippedfn + (size - 3); - } - - if(0 != loc && size > 3 && 0 == strcasecmp(ext, ".so")) { - Q_strcpy(loc, ".so"); - META_DEBUG(4, ("Checking for new version game DLL name '%s'.\n", strippedfn) ); - - // Again, as above, I abuse the real_pathname member to store the full pathname - // and the pathname member to store the relative name to pass it to the - // install_gamedll function to save stack space. They are going - // to get overwritten later on, so that's ok. - safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "dlls/%s", - strippedfn); - // Check if the gamedll file exists. If not, try to install it from - // the cache. - mBOOL ok = mTRUE; - if(!valid_gamedir_file(gamedll->pathname)) { - safevoid_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), "%s/dlls/%s", - gamedll->gamedir, strippedfn); - ok = install_gamedll(gamedll->pathname, gamedll->real_pathname); - } - if(ok) - usedfn = strippedfn; - } - else { - META_DEBUG(4, ("Known game DLL name does not qualify for checking for a stripped version, skipping: '%s'.\n", - strippedfn) ); - } -#endif /* linux */ - // If no file to be used was found, try the old known DLL file - // name. - if (0 == usedfn) { - META_DEBUG(4, ("Checking for old version game DLL name '%s'.\n", knownfn) ); - safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "dlls/%s", knownfn); - // Check if the gamedll file exists. If not, try to install it from - // the cache. - if(!valid_gamedir_file(gamedll->pathname)) { - safevoid_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), "%s/dlls/%s", - gamedll->gamedir, knownfn); - install_gamedll(gamedll->pathname, gamedll->real_pathname); - } - } else { - knownfn = usedfn; - } - } - } - - // Then, autodetect gamedlls in "gamedir/dlls/" - // autodetect_gamedll returns 0 if knownfn exists and is valid gamedll. - if(Config->autodetect && (autofn=autodetect_gamedll(gamedll, knownfn))) { - // If knownfn is set and autodetect_gamedll returns non-null - // then knownfn doesn't exists and we should use autodetected - // dll instead. - if(knownfn) { - // Whine loud about fact that known-list dll doesn't exists! - //META_LOG(plapla); - knownfn = autofn; - } - } - - // Neither override nor known-list nor auto-detect found a gamedll. - if(!known && !Config->gamedll && !autofn) - RETURN_ERRNO(mFALSE, ME_NOTFOUND); - - // Use override-dll if specified. - if(Config->gamedll) { - STRNCPY(gamedll->pathname, Config->gamedll, - sizeof(gamedll->pathname)); - override=1; - - // If the path is relative, the gamedll file will be missing and - // it might be found in the cache file. - if(!is_absolute_path(gamedll->pathname)) { - safevoid_snprintf(install_path, sizeof(install_path), - "%s/%s", gamedll->gamedir, gamedll->pathname); - // If we could successfully install the gamedll from the cache we - // rectify the pathname to be a full pathname. - if(install_gamedll(gamedll->pathname, install_path)) - STRNCPY(gamedll->pathname, install_path, sizeof(gamedll->pathname)); - } - } - // Else use Known-list dll. - else if(known) { - safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "%s/dlls/%s", - gamedll->gamedir, knownfn); - } - // Else use Autodetect dll. - else { - safevoid_snprintf(gamedll->pathname, sizeof(gamedll->pathname), "%s/dlls/%s", - gamedll->gamedir, autofn); - } - - // get filename from pathname - cp=Q_strrchr(gamedll->pathname, '/'); - if(cp) - cp++; - else - cp=gamedll->pathname; - gamedll->file=cp; - - // If found, store also the supposed "real" dll path based on the - // gamedir, in case it differs from the "override" dll path. - if(known && override) - safevoid_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), - "%s/dlls/%s", gamedll->gamedir, knownfn); - else if(known && autofn) - safevoid_snprintf(gamedll->real_pathname, sizeof(gamedll->real_pathname), - "%s/dlls/%s", gamedll->gamedir, knownfn); - else // !known or (!override and !autofn) - STRNCPY(gamedll->real_pathname, gamedll->pathname, - sizeof(gamedll->real_pathname)); - - if(override) { - // generate a desc - safevoid_snprintf(override_desc_buf, sizeof(override_desc_buf), "%s (override)", gamedll->file); - gamedll->desc=override_desc_buf; - // log result - META_LOG("Overriding game '%s' with dllfile '%s'", gamedll->name, gamedll->file); - } - else if(known && autofn) { - // dll in known-list doesn't exists but we found new one with autodetect. - - // generate a desc - safevoid_snprintf(autodetect_desc_buf, sizeof(autodetect_desc_buf), "%s (autodetect-override)", gamedll->file); - gamedll->desc=autodetect_desc_buf; - META_LOG("Recognized game '%s'; Autodetection override; using dllfile '%s'", gamedll->name, gamedll->file); - } - else if(autofn) { - // generate a desc - safevoid_snprintf(autodetect_desc_buf, sizeof(autodetect_desc_buf), "%s (autodetect)", gamedll->file); - gamedll->desc=autodetect_desc_buf; - META_LOG("Autodetected game '%s'; using dllfile '%s'", gamedll->name, gamedll->file); - } - else if(known) { - gamedll->desc=known->desc; - META_LOG("Recognized game '%s'; using dllfile '%s'", gamedll->name, gamedll->file); - } - return(mTRUE); -} diff --git a/src/games.h b/src/games.h deleted file mode 100644 index 5b241ae..0000000 --- a/src/games.h +++ /dev/null @@ -1,99 +0,0 @@ - -// This list is now kept in a separate file to facilitate generating the -// list from game data stored in a convenient db. - -#if defined(__x86_64__) || defined(__amd64__) -# define MODARCH "_amd64" -#else -# define MODARCH "_i386" -#endif -/* - {"action", "ahl"MODARCH".so", "ahl.dll", "Action Half-Life"}, - {"ag", "ag"MODARCH".so", "ag.dll", "Adrenaline Gamer Steam"}, - {"ag3", "hl"MODARCH".so", "hl.dll", "Adrenalinegamer 3.x"}, - {"aghl", "ag"MODARCH".so", "ag.dll", "Adrenalinegamer 4.x"}, - {"arg", "arg"MODARCH".so", "hl.dll", "Arg!"}, - {"asheep", "hl"MODARCH".so", "hl.dll", "Azure Sheep"}, - {"bg", "bg"MODARCH".so", "bg.dll", "The Battle Grounds"}, - {"bot", "bot"MODARCH".so", "bot.dll", "Bot"}, - {"brainbread", "bb"MODARCH".so", "bb.dll", "Brain Bread"}, - {"bumpercars", "hl"MODARCH".so", "hl.dll", "Bumper Cars"}, - {"buzzybots", "bb"MODARCH".so", "bb.dll", "BuzzyBots"}, - {"cs13", "cs"MODARCH".so", "mp.dll", "Counter-Strike 1.3"}, -*/ - {"cstrike", "cs"MODARCH".so", "mp.dll", "Counter-Strike"}, - //{"csv15", "cs"MODARCH".so", "mp.dll", "CS 1.5 for Steam"}, - {"czero", "cs"MODARCH".so", "mp.dll", "Counter-Strike:Condition Zero"}, -/* - {"dcrisis", "dc"MODARCH".so", "dc.dll", "Desert Crisis"}, - {"dmc", "dmc"MODARCH".so", "dmc.dll", "Deathmatch Classic"}, - {"dod", "dod"MODARCH".so", "dod.dll", "Day of Defeat"}, - {"dpb", "pb.i386.so", "pb.dll", "Digital Paintball"}, - {"dragonmodz", "hl"MODARCH".so", "mp.dll", "Dragon Mod Z"}, - {"esf", "hl"MODARCH".so", "hl.dll", "Earth's Special Forces"}, - {"existence", "ex"MODARCH".so", "existence.dll", "Existence"}, - {"firearms", "fa"MODARCH".so", "firearms.dll", "Firearms"}, - {"firearms25", "fa"MODARCH".so", "firearms.dll", "Retro Firearms"}, - {"freeze", "mp"MODARCH".so", "mp.dll", "Freeze"}, - {"frontline", "front"MODARCH".so", "frontline.dll", "Frontline Force"}, - {"gangstawars", "gangsta"MODARCH".so", "gwars27.dll", "Gangsta Wars"}, - {"gangwars", "mp"MODARCH".so", "mp.dll", "Gangwars"}, - {"gearbox", "opfor"MODARCH".so", "opfor.dll", "Opposing Force"}, - {"globalwarfare", "gw"MODARCH".so", "mp.dll", "Global Warfare"}, - {"goldeneye", "golden"MODARCH".so", "mp.dll", "Goldeneye"}, - {"hl15we", "hl"MODARCH".so", "hl.dll", "Half-Life 1.5: Weapon Edition"}, - {"hlrally", "hlr"MODARCH".so", "hlrally.dll", "HL-Rally"}, - {"holywars", "hl"MODARCH".so", "holywars.dll", "Holy Wars"}, - {"hostileintent", "hl"MODARCH".so", "hl.dll", "Hostile Intent"}, - {"ios", "ios"MODARCH".so", "ios.dll", "International Online Soccer"}, - {"judgedm", "judge"MODARCH".so", "mp.dll", "Judgement"}, - {"kanonball", "hl"MODARCH".so", "kanonball.dll", "Kanonball"}, - {"monkeystrike", "ms"MODARCH".so", "monkey.dll", "Monkeystrike"}, - {"MorbidPR", "morbid"MODARCH".so", "morbid.dll", "Morbid Inclination"}, - {"movein", "hl"MODARCH".so", "hl.dll", "Move In!"}, - {"ns", "ns"MODARCH".so", "ns.dll", "Natural Selection"}, - {"nsp", "ns"MODARCH".so", "ns.dll", "Natural Selection Beta"}, - {"oel", "hl"MODARCH".so", "hl.dll", "OeL Half-Life"}, - {"og", "og"MODARCH".so", "og.dll", "Over Ground"}, - {"ol", "ol"MODARCH".so", "hl.dll", "Outlawsmod"}, - {"ops1942", "spirit"MODARCH".so", "spirit.dll", "Operations 1942"}, - {"osjb", "osjb"MODARCH".so", "jail.dll", "Open-Source Jailbreak"}, - {"outbreak", "none", "hl.dll", "Out Break"}, - {"oz", "mp"MODARCH".so", "mp.dll", "Oz Deathmatch"}, - {"paintball", "pb"MODARCH".so", "mp.dll", "Paintball"}, - {"penemy", "pe"MODARCH".so", "pe.dll", "Public Enemy"}, - {"phineas", "phineas"MODARCH".so", "phineas.dll", "Phineas Bot"}, - {"ponreturn", "ponr"MODARCH".so", "mp.dll", "Point of No Return"}, - {"pvk", "hl"MODARCH".so", "hl.dll", "Pirates, Vikings and Knights"}, - {"rc2", "rc2"MODARCH".so", "rc2.dll", "Rocket Crowbar 2"}, - {"retrocs", "rcs"MODARCH".so", "rcs.dll", "Retro Counter-Strike"}, - {"rewolf", "hl"MODARCH".so", "gunman.dll", "Gunman Chronicles"}, - {"ricochet", "ricochet"MODARCH".so", "mp.dll", "Ricochet"}, - {"rockcrowbar", "rc"MODARCH".so", "rc.dll", "Rocket Crowbar"}, - {"rspecies", "hl"MODARCH".so", "hl.dll", "Rival Species"}, - {"scihunt", "shunt.so", "shunt.dll", "Scientist Hunt"}, - {"sdm", "sdmmod"MODARCH".so", "sdmmod.dll", "Special Death Match"}, - {"Ship", "ship"MODARCH".so", "ship.dll", "The Ship"}, - {"si", "si"MODARCH".so", "si.dll", "Science & Industry"}, - {"snow", "snow"MODARCH".so", "snow.dll", "Snow-War"}, - {"stargatetc", "hl"MODARCH".so", "hl.dll", "StargateTC"}, - {"svencoop", "hl"MODARCH".so", "hl.dll", "Sven Coop"}, - {"swarm", "swarm"MODARCH".so", "swarm.dll", "Swarm"}, - {"tfc", "tfc"MODARCH".so", "tfc.dll", "Team Fortress Classic"}, - {"thewastes", "thewastes"MODARCH".so", "thewastes.dll", "The Wastes"}, - {"timeless", "pt"MODARCH".so", "timeless.dll", "Project Timeless"}, - {"tod", "hl"MODARCH".so", "hl.dll", "Tour of Duty"}, - {"trainhunters", "th"MODARCH".so", "th.dll", "Train Hunters"}, - {"trevenge", "trevenge.so", "trevenge.dll", "The Terrorist Revenge"}, - {"TS", "ts"MODARCH".so", "mp.dll", "The Specialists"}, - {"tt", "tt"MODARCH".so", "tt.dll", "The Trenches"}, - {"underworld", "uw"MODARCH".so", "uw.dll", "Underworld Bloodline"}, - {"valve", "hl"MODARCH".so", "hl.dll", "Half-Life Deathmatch"}, - {"vs", "vs"MODARCH".so", "mp.dll", "VampireSlayer"}, - {"wantedhl", "hl"MODARCH".so", "wanted.dll", "Wanted!"}, - {"wasteland", "whl_linux.so", "mp.dll", "Wasteland"}, - {"weapon_wars", "ww"MODARCH".so", "hl.dll", "Weapon Wars"}, - {"wizwars", "mp"MODARCH".so", "hl.dll", "Wizard Wars"}, - {"wormshl", "wormshl_i586.so", "wormshl.dll", "WormsHL"}, - {"zp", "none", "mp.dll", "Zombie Panic"}, -*/ diff --git a/src/info_name.h b/src/info_name.h deleted file mode 100644 index eab8e33..0000000 --- a/src/info_name.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef INFO_NAME_H -#define INFO_NAME_H - -#include "vers_meta.h" // VDATE, VVERSION, etc - -#define VNAME "Metamod" -#define VAUTHOR "Will Day" -#define VURL "http://www.metamod.org/" - -#define COPYRIGHT_YEAR "2013" - -// Various strings for the Windows DLL Resources in res_meta.rc -#define RC_COMMENTS "Metamod-P is enhanced version of Metamod. Metamod allows running multiple mod-like plugin DLLs, to add functionality or change the behavior of the running HLDS game mod. See " VURL -#define RC_DESC "Metamod-P Half-Life MOD DLL" -#define RC_FILENAME "METAMOD.DLL" -#define RC_INTERNAL "METAMOD-P" -#define RC_COPYRIGHT "Copyright© 2001-" COPYRIGHT_YEAR " Will Day; 2004-" VPATCH_COPYRIGHT_YEAR " Jussi Kivilinna; GPL licensed" -#define RC_LICENSE "Licensed under the GNU General Public License" - -#endif /* INFO_NAME_H */ diff --git a/src/meta_eiface.h b/src/meta_eiface.h deleted file mode 100644 index db29591..0000000 --- a/src/meta_eiface.h +++ /dev/null @@ -1,437 +0,0 @@ -#ifndef MM_META_EIFACE_H -#define MM_META_EIFACE_H - -#include // NEW_DLL_FUNCTIONS, enginefuncs_t -#include // memset() -#include "comp_dep.h" -#include "osdep.h" //unlikely, OPEN_ARGS - -// We use our own versions of the engine/dll interface structs. We add a -// few dummy entries to the end and set them to 0. That way we are -// protected from updates to the HL SDK adding new functions which would -// cause a) the game dll copying arbitrary values from us and b) the game -// dll overwriting our memory when using an old Metamod with a new game -// dll. - -const int c_NumDummies = 5; -typedef void (*pdummyfunc)(void); - -// -------------------------------------------------------------------- -// meta_new_dll_functions_t -// -------------------------------------------------------------------- - -struct meta_new_dll_functions_t : public NEW_DLL_FUNCTIONS { - // Array of five dummy function pointers. Must be filled with NULL. - pdummyfunc dummies[c_NumDummies]; - - // functions : - meta_new_dll_functions_t() DLLINTERNAL; - - meta_new_dll_functions_t( - void (*pfnOnFreeEntPrivateData) (edict_t*), - void (*pfnGameShutdown) (void), - int (*pfnShouldCollide) (edict_t*, edict_t*), - void (*pfnCvarValue) (const edict_t*, const char*), - void (*pfnCvarValue2) (const edict_t*, int, const char*, const char*) - ) DLLINTERNAL; - - meta_new_dll_functions_t( const meta_new_dll_functions_t& ) DLLINTERNAL; - meta_new_dll_functions_t& operator=( const meta_new_dll_functions_t& ) DLLINTERNAL; - - // Fill this object with pointers copied from a NEW_DLL_FUNCTIONS struct. - void DLLINTERNAL set_from( NEW_DLL_FUNCTIONS* pFuncs ); - - // Copy the pointers from this object to a NEW_DLL_FUNCTIONS struct. - void DLLINTERNAL copy_to( NEW_DLL_FUNCTIONS* pFuncs ); - - // return the engine's version of NEW_DLL_FUNCTIONS - int DLLINTERNAL version( void ); - - private: - - // data : - - // The NEW_DLL_FUNCTIONS struct also changed, but the version - // number did not change. That begs the question why to have - // it versioned in the first place, but whaddaya know. - // While the official version is left at 1, we internally - // calculate a different version of the engine's NEW_DLL_FUNCTIONS - // struct since we know that the engine lies to us about the - // version that it uses. - // - // The default version is 1. - // - // With the enginefuncs interface version 156 the function - // pfnCvarValue() was added, which we call version 2. - // - // With the enginefuncs interface version 157 the function - // pfnCvarValue2() was added, which we call version 3. - // - // If Valve ever decides to change the version of the - // NEW_DLL_FUNCTIONS interface in the future (haha), - // we are in trouble and will need to change our - // internal versions. - - static int sm_version; - - // functions : - - // Calculates our idea of the engine's version of the - // NEW_DLL_FUNCTIONS interface. Stores this version for future - // reference in m_version and returns it. - int DLLINTERNAL determine_interface_version( void ); - - // Comfort function to determine the size of the NEW_DLL_FUNCTIONS - // struct for the different versions. - // If passed a version number other than 0, the size for that - // specific version is returned. - // If passed 0 as version number (default) the size for the version - // that was determined to be the version of the currently connected - // engine's interface. Should that version have not yet been - // determined (via the enginefuncs_t interface), 0 is returned to - // indicated this error state. - size_t DLLINTERNAL get_size( int version = 0 ); -}; - - -// Inline functions - -inline meta_new_dll_functions_t::meta_new_dll_functions_t() -{ - Q_memset( this, 0, sizeof(meta_new_dll_functions_t) ); -} - - -inline meta_new_dll_functions_t::meta_new_dll_functions_t( const meta_new_dll_functions_t& _rhs ) -{ - Q_memcpy( this, &_rhs, sizeof(NEW_DLL_FUNCTIONS) ); - Q_memset( dummies, 0, sizeof(pdummyfunc) * c_NumDummies ); -} - - -inline meta_new_dll_functions_t& meta_new_dll_functions_t::operator=( const meta_new_dll_functions_t& _rhs) -{ - Q_memcpy( this, &_rhs, sizeof(NEW_DLL_FUNCTIONS) ); - return *this; -} - - -inline void meta_new_dll_functions_t::set_from( NEW_DLL_FUNCTIONS* _pFuncs ) -{ - Q_memcpy( this, _pFuncs, sizeof(NEW_DLL_FUNCTIONS) ); -} - - -inline int meta_new_dll_functions_t::version( void ) -{ - return sm_version ? sm_version : determine_interface_version(); -} - - -// No meta version of DLL_FUNCTIONS because that won't be changing anymore. - - -// -------------------------------------------------------------------- -// meta_enginefuncs_t -// -------------------------------------------------------------------- - - -struct meta_enginefuncs_t : public enginefuncs_t { - // data : - - // Array of five dummy function pointers. Must be filled with NULL. - pdummyfunc dummies[c_NumDummies]; - - // functions : - meta_enginefuncs_t() DLLINTERNAL; - - // Spawn of the devil - meta_enginefuncs_t( - int (*_pfnPrecacheModel) (const char*), - int (*_pfnPrecacheSound) (const char*), - void (*_pfnSetModel) (edict_t*, const char*), - int (*_pfnModelIndex) (const char*), - int (*_pfnModelFrames) (int), - void (*_pfnSetSize) (edict_t*, const float*, const float*), - void (*_pfnChangeLevel) (const char*, const char*), - void (*_pfnGetSpawnParms) (edict_t*), - void (*_pfnSaveSpawnParms) (edict_t*), - float (*_pfnVecToYaw) (const float*), - void (*_pfnVecToAngles) (const float*, float*), - void (*_pfnMoveToOrigin) (edict_t*, const float*, float, int), - void (*_pfnChangeYaw) (edict_t*), - void (*_pfnChangePitch) (edict_t*), - edict_t* (*_pfnFindEntityByString) (edict_t*, const char*, const char*), - int (*_pfnGetEntityIllum) (edict_t*), - edict_t* (*_pfnFindEntityInSphere) (edict_t*, const float*, float), - edict_t* (*_pfnFindClientInPVS) (edict_t*), - edict_t* (*_pfnEntitiesInPVS) (edict_t*), - void (*_pfnMakeVectors) (const float*), - void (*_pfnAngleVectors) (const float*, float*, float*, float*), - edict_t* (*_pfnCreateEntity) (void), - void (*_pfnRemoveEntity) (edict_t*), - edict_t* (*_pfnCreateNamedEntity) (int), - void (*_pfnMakeStatic) (edict_t*), - int (*_pfnEntIsOnFloor) (edict_t*), - int (*_pfnDropToFloor) (edict_t*), - int (*_pfnWalkMove) (edict_t*, float, float, int), - void (*_pfnSetOrigin) (edict_t*, const float*), - void (*_pfnEmitSound) (edict_t*, int, const char*, float, float, int, int), - void (*_pfnEmitAmbientSound) (edict_t*, float*, const char*, float, float, int, int), - void (*_pfnTraceLine) (const float*, const float*, int, edict_t*, TraceResult*), - void (*_pfnTraceToss) (edict_t*, edict_t*, TraceResult*), - int (*_pfnTraceMonsterHull) (edict_t*, const float*, const float*, int, edict_t*, TraceResult*), - void (*_pfnTraceHull) (const float*, const float*, int, int, edict_t*, TraceResult*), - void (*_pfnTraceModel) (const float*, const float*, int, edict_t*, TraceResult*), - const char* (*_pfnTraceTexture) (edict_t*, const float*, const float*), - void (*_pfnTraceSphere) (const float*, const float*, int, float, edict_t*, TraceResult*), - void (*_pfnGetAimVector) (edict_t*, float, float*), - void (*_pfnServerCommand) (const char*), - void (*_pfnServerExecute) (void), - void (*_pfnClientCommand) (edict_t*, const char*, ...), - void (*_pfnParticleEffect) (const float*, const float*, float, float), - void (*_pfnLightStyle) (int, const char*), - int (*_pfnDecalIndex) (const char*), - int (*_pfnPointContents) (const float*), - void (*_pfnMessageBegin) (int, int, const float*, edict_t*), - void (*_pfnMessageEnd) (void), - void (*_pfnWriteByte) (int), - void (*_pfnWriteChar) (int), - void (*_pfnWriteShort) (int), - void (*_pfnWriteLong) (int), - void (*_pfnWriteAngle) (float), - void (*_pfnWriteCoord) (float), - void (*_pfnWriteString) (const char*), - void (*_pfnWriteEntity) (int), - void (*_pfnCVarRegister) (cvar_t*), - float (*_pfnCVarGetFloat) (const char*), - const char* (*_pfnCVarGetString) (const char*), - void (*_pfnCVarSetFloat) (const char*, float), - void (*_pfnCVarSetString) (const char*, const char*), - void (*_pfnAlertMessage) (ALERT_TYPE, const char*, ...), - void (*_pfnEngineFprintf) (void*, const char*, ...), - void* (*_pfnPvAllocEntPrivateData) (edict_t*, int32), - void* (*_pfnPvEntPrivateData) (edict_t*), - void (*_pfnFreeEntPrivateData) (edict_t*), - const char* (*_pfnSzFromIndex) (int), - int (*_pfnAllocString) (const char*), - struct entvars_s*(*_pfnGetVarsOfEnt) (edict_t*), - edict_t* (*_pfnPEntityOfEntOffset) (int), - int (*_pfnEntOffsetOfPEntity) (const edict_t*), - int (*_pfnIndexOfEdict) (const edict_t*), - edict_t* (*_pfnPEntityOfEntIndex) (int), - edict_t* (*_pfnFindEntityByVars) (struct entvars_s*), - void* (*_pfnGetModelPtr) (edict_t*), - int (*_pfnRegUserMsg) (const char*, int), - void (*_pfnAnimationAutomove) (const edict_t*, float), - void (*_pfnGetBonePosition) (const edict_t*, int, float*, float* ), - uint32 (*_pfnFunctionFromName) (const char*), - const char* (*_pfnNameForFunction) (uint32), - void (*_pfnClientPrintf) (edict_t*, PRINT_TYPE, const char*), - void (*_pfnServerPrint) (const char*), - const char* (*_pfnCmd_Args) (void), - const char* (*_pfnCmd_Argv) (int argc), - int (*_pfnCmd_Argc) (void), - void (*_pfnGetAttachment) (const edict_t*, int, float*, float*), - void (*_pfnCRC32_Init) (CRC32_t*), - void (*_pfnCRC32_ProcessBuffer) (CRC32_t*, void*, int), - void (*_pfnCRC32_ProcessByte) (CRC32_t*, unsigned char), - CRC32_t (*_pfnCRC32_Final) (CRC32_t), - int32 (*_pfnRandomLong) (int32, int32), - float (*_pfnRandomFloat) (float, float), - void (*_pfnSetView) (const edict_t*, const edict_t*), - float (*_pfnTime) (void), - void (*_pfnCrosshairAngle) (const edict_t*, float, float), - byte* (*_pfnLoadFileForMe) (const char*, int*), - void (*_pfnFreeFile) (void*), - void (*_pfnEndSection) (const char*), - int (*_pfnCompareFileTime) (char*, char*, int*), - void (*_pfnGetGameDir) (char*), - void (*_pfnCvar_RegisterVariable) (cvar_t*), - void (*_pfnFadeClientVolume) (const edict_t*, int, int, int, int), - void (*_pfnSetClientMaxspeed) (const edict_t*, float), - edict_t* (*_pfnCreateFakeClient) (const char*), - void (*_pfnRunPlayerMove) (edict_t*, const float*, float, float, float, unsigned short, byte, byte), - int (*_pfnNumberOfEntities) (void), - char* (*_pfnGetInfoKeyBuffer) (edict_t*), - char* (*_pfnInfoKeyValue) (char*, const char*), - void (*_pfnSetKeyValue) (char*, const char*, const char*), - void (*_pfnSetClientKeyValue) (int, char*, const char*, const char*), - int (*_pfnIsMapValid) (const char*), - void (*_pfnStaticDecal) (const float*, int, int, int), - int (*_pfnPrecacheGeneric) (const char*), - int (*_pfnGetPlayerUserId) (edict_t*), - void (*_pfnBuildSoundMsg) (edict_t*, int, const char*, float, float, int, int, int, int, const float*, edict_t*), - int (*_pfnIsDedicatedServer) (void), - cvar_t* (*_pfnCVarGetPointer) (const char*), - unsigned int (*_pfnGetPlayerWONId) (edict_t*), - void (*_pfnInfo_RemoveKey) (char*, const char*), - const char* (*_pfnGetPhysicsKeyValue) (const edict_t*, const char*), - void (*_pfnSetPhysicsKeyValue) (const edict_t*, const char*, const char*), - const char* (*_pfnGetPhysicsInfoString) (const edict_t*), - unsigned short (*_pfnPrecacheEvent) (int, const char*), - void (*_pfnPlaybackEvent) (int, const edict_t*, unsigned short, float, float*, float*, float, float, int, int, int, int), - unsigned char* (*_pfnSetFatPVS) (float*), - unsigned char* (*_pfnSetFatPAS) (float*), - int (*_pfnCheckVisibility) (const edict_t*, unsigned char*), - void (*_pfnDeltaSetField) (struct delta_s*, const char*), - void (*_pfnDeltaUnsetField) (struct delta_s*, const char*), - void (*_pfnDeltaAddEncoder) (const char*, void (*)(struct delta_s*, const unsigned char*, const unsigned char*)), - int (*_pfnGetCurrentPlayer) (void), - int (*_pfnCanSkipPlayer) (const edict_t*), - int (*_pfnDeltaFindField) (struct delta_s*, const char*), - void (*_pfnDeltaSetFieldByIndex) (struct delta_s*, int), - void (*_pfnDeltaUnsetFieldByIndex) (struct delta_s*, int), - void (*_pfnSetGroupMask) (int, int), - int (*_pfnCreateInstancedBaseline) (int, struct entity_state_s*), - void (*_pfnCvar_DirectSet) (struct cvar_s*, const char*), - void (*_pfnForceUnmodified) (FORCE_TYPE, float*, float*, const char*), - void (*_pfnGetPlayerStats) (const edict_t*, int*, int*), - void (*_pfnAddServerCommand) (const char*, void (*) (void)), - qboolean (*_pfnVoice_GetClientListening) (int, int), - qboolean (*_pfnVoice_SetClientListening) (int, int, qboolean), - const char* (*_pfnGetPlayerAuthId) (edict_t*), - sequenceEntry_s* (*_pfnSequenceGet) (const char*, const char*), - sentenceEntry_s* (*_pfnSequencePickSentence) (const char*, int, int*), - int (*_pfnGetFileSize) (const char*), - unsigned int (*_pfnGetApproxWavePlayLen) (const char*), - int (*_pfnIsCareerMatch) (void), - int (*_pfnGetLocalizedStringLength) (const char*), - void (*_pfnRegisterTutorMessageShown) (int), - int (*_pfnGetTimesTutorMessageShown) (int), - void (*_pfnProcessTutorMessageDecayBuffer) (int*, int), - void (*_pfnConstructTutorMessageDecayBuffer)(int*, int), - void (*_pfnResetTutorMessageDecayData) (void), - void (*_pfnQueryClientCvarValue) (const edict_t*, const char*), - void (*_pfnQueryClientCvarValue2) (const edict_t*, const char*, int), - int (*_pfnCheckParm) (const char *, char**) - ) DLLINTERNAL; - - meta_enginefuncs_t( const meta_enginefuncs_t& ) DLLINTERNAL; - meta_enginefuncs_t& operator=( const meta_enginefuncs_t& ) DLLINTERNAL; - - // Fill this object with pointers copied from an enginefuncs_t struct. - void DLLINTERNAL set_from( enginefuncs_t *pFuncs ); - - // Copy the pointers from this object to an enginefuncs_t struct. - void DLLINTERNAL copy_to( enginefuncs_t *pFuncs ); - - // return the engine interface version - static int DLLINTERNAL version( void ); - - protected: - - // data : - - // The version of the engine functions interface. It is frozen at 138. But no one knows - // when that was and what it looked like then. So we simply interprete it as the - // number of functions that the enginefuncs struct contains. - // - // That means we get gaps inbetween versions and right now we can detect only - // about five different versions anyway, but that suffices for the current itches - // to get scratched. - // - // The default is hence 138. - // A value of 0 means "not yet determined". - // Other possible versions currently detectable: - // 144: engine versions after 1.1.0.9 build 1996 - // 147: engine versions after build 2384 with pfnGetFileSize() - // 155: all versions between build 2384 and the one - // including pfnQueryClientCvarValue() - // 156: includes pfnQueryClientCvarValue() - // 157: includes pfnQueryClientCvarValue2() - // 158: includes pfnCheckParm() - static int sm_version DLLHIDDEN; - -}; - -// -// Inline functions -// - -inline meta_enginefuncs_t::meta_enginefuncs_t() -{ - Q_memset( this, 0, sizeof(meta_enginefuncs_t) ); -} - - -inline meta_enginefuncs_t::meta_enginefuncs_t( const meta_enginefuncs_t& _rhs ) -{ - Q_memcpy( this, &_rhs, sizeof(enginefuncs_t) ); - Q_memset( dummies, 0, sizeof(pdummyfunc) * c_NumDummies ); -} - - -inline meta_enginefuncs_t& meta_enginefuncs_t::operator=( const meta_enginefuncs_t& _rhs) -{ - Q_memcpy( this, &_rhs, sizeof(enginefuncs_t) ); - return *this; -} - - -inline void meta_enginefuncs_t::set_from( enginefuncs_t* _pFuncs ) -{ - Q_memcpy( this, _pFuncs, sizeof(enginefuncs_t) ); -} - - -inline void meta_enginefuncs_t::copy_to( enginefuncs_t* _pFuncs ) -{ - Q_memcpy( _pFuncs, this, sizeof(enginefuncs_t) ); -} - - -inline int meta_enginefuncs_t::version( void ) -{ - return sm_version; -} - - - -// -------------------------------------------------------------------- -// HL_enginefuncs_t -// -------------------------------------------------------------------- - -// -// This is a specialisation of the meta_enginefuncs_t struct which is only -// used for the initial copy of the engine functions, i.e. those we get -// passed from the HL engine right at the beginning. -// This specialisation does some extra initialisation when getting set up -// like calculating the engine interface version and fixing up any invalid -// pointers. -// Since there is only one master copy of engine functions this could be -// implemented as a singleton. This is left as an option for later. -// -struct HL_enginefuncs_t : public meta_enginefuncs_t { - - // functions : - HL_enginefuncs_t() DLLINTERNAL; - - // Fill this object with pointers copied from an enginefuncs_t struct - // and fixup the interface. - // For this class this happens in the GiveFptrsToDll() function - // with the pointers passed from the HL engine. - void initialise_interface( enginefuncs_t *pFuncs ) DLLINTERNAL; - - private: - - // functions : - - // Moving copy_to() and set_from() to the private space. - void DLLINTERNAL set_from( enginefuncs_t *pFuncs ) { meta_enginefuncs_t::set_from( pFuncs ); }; - void DLLINTERNAL copy_to( enginefuncs_t *pFuncs ) { meta_enginefuncs_t::copy_to( pFuncs ); }; - - // Determine the version of the engine interface from the - // enginefuncs signature. - void DLLINTERNAL determine_engine_interface_version( void ); - - // Fixup the enginefuncs pointers according to the determined - // version as some pointers may be invalid. - void DLLINTERNAL fixup_engine_interface( void ); -}; - - -inline HL_enginefuncs_t :: HL_enginefuncs_t() : meta_enginefuncs_t() { }; - - -#endif /* META_EIFACE_H */ diff --git a/src/mlist.h b/src/mlist.h deleted file mode 100644 index e9afa05..0000000 --- a/src/mlist.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MLIST_H -#define MLIST_H - -#include "types_meta.h" // mBOOL -#include "mplugin.h" // class MPlugin -#include "plinfo.h" // plid_t, etc -#include "new_baseclass.h" - -// Max number of plugins we can manage. This is an arbitrary, fixed number, -// for convenience. It would probably be better to dynamically grow the -// list as needed, but we do this for now. -#define MAX_PLUGINS 50 -// Width required to printf above MAX, for show() functions. -#define WIDTH_MAX_PLUGINS 2 - -// A list of plugins. -class MPluginList : public class_metamod_new { - public: - // data: - MPlugin plist[MAX_PLUGINS]; // array of plugins - int size; // size of list, ie MAX_PLUGINS - int endlist; // index of last used entry - char inifile[PATH_MAX]; // full pathname - // constructor: - MPluginList(const char *ifile) DLLINTERNAL; - // functions: - void DLLINTERNAL reset_plugin(MPlugin *pl_find); - MPlugin * DLLINTERNAL find(int pindex); // find by index - MPlugin * DLLINTERNAL find(const char *findpath); // find by pathname - MPlugin * DLLINTERNAL find(plid_t id); // find by plid_t - MPlugin * DLLINTERNAL find(DLHANDLE handle); // find by handle - MPlugin * DLLINTERNAL find_memloc(void *memptr); // find by memory location - MPlugin * DLLINTERNAL find_match(const char *prefix); // find by partial prefix match - MPlugin * DLLINTERNAL find_match(MPlugin *pmatch); // find by platform_match() - MPlugin * DLLINTERNAL add(MPlugin *padd); - mBOOL DLLINTERNAL found_child_plugins(int source_index); - void DLLINTERNAL clear_source_plugin_index(int source_index); - void DLLINTERNAL trim_list(void); - mBOOL DLLINTERNAL ini_startup(void); // read inifile at startup - mBOOL DLLINTERNAL ini_refresh(void); // re-read inifile - mBOOL DLLINTERNAL cmd_addload(const char *args); // load from console command - MPlugin * DLLINTERNAL plugin_addload(plid_t plid, const char *fname, PLUG_LOADTIME now); //load from plugin - mBOOL DLLINTERNAL load(void); // load the list, at startup - mBOOL DLLINTERNAL refresh(PLUG_LOADTIME now); // update from re-read inifile - void DLLINTERNAL unpause_all(void); // unpause any paused plugins - void DLLINTERNAL retry_all(PLUG_LOADTIME now); // retry any pending plugin actions - void DLLINTERNAL show(int source_index); // list plugins to console - void DLLINTERNAL show(void) { show(-1); }; // list plugins to console - void DLLINTERNAL show_client(edict_t *pEntity); // list plugins to player client -}; - -#endif /* MLIST_H */ diff --git a/src/mm_pextensions.h b/src/mm_pextensions.h deleted file mode 100644 index c61ef8b..0000000 --- a/src/mm_pextensions.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MM_PEXTENSIONS_H -#define MM_PEXTENSIONS_H - -#include "plinfo.h" // plid_t -#include "meta_api.h" // PLUG_LOADTIME -/* - - How to use: - 1. Add new export function 'Meta_PExtGiveFnptrs' to your plugin file. - 'Meta_PExtGiveFnptrs' will be called right after 'Meta_Query' call. - 2. Meta_PExtGiveFnptrs is called with interface version 'META_PEXT_VERSION' - and pointer to extension function table. - 3. Meta_PExtGiveFnptrs should return plugin's interface version. - 4. !NOTE! Metamod will not stop loading plugin even if plugin returns - interface version greater than current. Plugin should disable itself in - this kind of situation. - - Example: - #include "mm_pextensions.h" - - pextension_funcs_t *gpMetaPExtFuncs; - - int Meta_PExtGiveFnptrs(int interfaceVersion, pextension_funcs_t *pMetaPExtFuncs) { - if(interfaceVersion < META_PEXT_VERSION) { - LOG_DEVELOPER(PLID, "Error! Metamod is too old, please update!"); - gpMetaPExtFuncs = NULL; - - return(META_PEXT_VERSION); - } - - gpMetaPExtFuncs = pMetaPExtFuncs; - - return(META_PEXT_VERSION); - } - - Callback functions: - - int PEXT_LOAD_PLUGIN_BY_NAME(PLID, const char *cmdline, PLUG_LOADTIME now, void **plugin_handle); - Parses 'cmdline' as metamod would parse 'meta load ' and loads found - plugin. If 'plugin_handle' is set, metamod writes module handle of loaded - plugin at it. - Returns zero on success. - For error codes see 'META_ERRNO' in 'types_meta.h'. - - - int PEXT_UNLOAD_PLUGIN_BY_NAME(PLID, const char *cmdline, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); - Parses 'cmdline' as metamod would parse 'meta unload ' and - unloads found plugin. - Returns zero on success. - For error codes see 'META_ERRNO' in 'types_meta.h'. - - - int PEXT_UNLOAD_PLUGIN_BY_HANDLE(PLID, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); - Unloads plugin with 'plugin_handle'. - Returns zero on success. - For error codes see 'META_ERRNO' in 'types_meta.h'. - - !NOTE! Plugin cannot unload itself! -*/ - -// Interface version -// 1: first version. Used in p13 -// 2: Complete remake (p14): -// pfnLoadMetaPluginByName -// pfnUnloadMetaPluginByName -// pfnUnloadMetaPluginByHandle -// v2 is locked now. Don't modify old functions. If you add new functions, increase META_PEXT_VERSION. -#define META_PEXT_VERSION 2 - -// Meta PExtension Function table type. -typedef struct pextension_funcs_s { - int (*pfnLoadMetaPluginByName)(plid_t plid, const char *cmdline, PLUG_LOADTIME now, void **plugin_handle); - int (*pfnUnloadMetaPluginByName)(plid_t plid, const char *cmdline, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); - int (*pfnUnloadMetaPluginByHandle)(plid_t plid, void *plugin_handle, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); -} pextension_funcs_t; - -// Convenience macros for MetaPExtension functions. -#define PEXT_LOAD_PLUGIN_BY_NAME (*gpMetaPExtFuncs->pfnLoadMetaPluginByName) -#define PEXT_UNLOAD_PLUGIN_BY_NAME (*gpMetaPExtFuncs->pfnUnloadMetaPluginByName) -#define PEXT_UNLOAD_PLUGIN_BY_HANDLE (*gpMetaPExtFuncs->pfnUnloadMetaPluginByHandle) - -// Give plugin extension function table. -C_DLLEXPORT int Meta_PExtGiveFnptrs(int interfaceVersion, - pextension_funcs_t *pMetaPExtFuncs); -typedef int (*META_GIVE_PEXT_FUNCTIONS_FN) (int interfaceVersion, - pextension_funcs_t *pMetaPExtFuncs); - -#endif /* MM_PEXTENSIONS_H */ diff --git a/src/mplayer.h b/src/mplayer.h deleted file mode 100644 index b6bd454..0000000 --- a/src/mplayer.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef INCLUDE_METAMOD_PLAYER_H -#define INCLUDE_METAMOD_PLAYER_H - -#include "plinfo.h" // plugin_info_t, etc -#include "mutil.h" // query_callback_t -#include "types_meta.h" // mBOOL -#include "new_baseclass.h" // class_metamod_new - -// Numbers of players limit set by the engine -#define MAX_PLAYERS 32 - -// Info on an individual player -class MPlayer : public class_metamod_new -{ -private: - mBOOL isQueried; // is this player currently queried for a cvar value - char *cvarName; // name of the cvar if getting queried - MPlayer (const MPlayer&) DLLINTERNAL; - MPlayer& operator=(const MPlayer&) DLLINTERNAL; - -public: - MPlayer() DLLINTERNAL; - ~MPlayer() DLLINTERNAL; - void DLLINTERNAL set_cvar_query(const char *cvar); // mark this player as querying a client cvar - void DLLINTERNAL clear_cvar_query(const char *cvar=NULL); // unmark this player as querying a client cvar - const char *DLLINTERNAL is_querying_cvar(void); // check if a player is querying a cvar. returns - // NULL if not or the name of the cvar -}; - - -// A list of players. The number of max players is fixed and small enough -// to use an array. -class MPlayerList -{ -private: - enum { NUM_SLOTS = MAX_PLAYERS + 1 }; - - MPlayer players[NUM_SLOTS]; // array of players - -public: - void DLLINTERNAL set_player_cvar_query(const edict_t *pEntity, const char *cvar); - void DLLINTERNAL clear_player_cvar_query(const edict_t *pEntity, const char *cvar=NULL); - void DLLINTERNAL clear_all_cvar_queries(void); - const char *DLLINTERNAL is_querying_cvar(const edict_t *pEntity); -}; - -#endif /* INCLUDE_METAMOD_PLAYER_H */ diff --git a/src/mplugin.h b/src/mplugin.h deleted file mode 100644 index 284b87f..0000000 --- a/src/mplugin.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef MPLUGIN_H -#define MPLUGIN_H - -#include // time_t, etc -#include // malloc, etc -#include // DLL_FUNCTIONS, etc -#include "types_meta.h" // mBOOL -#include "meta_api.h" // GETENTITYAPI_FN, etc -#include "api_info.h" // dllapi_info, etc -#include "support_meta.h" // MAX_DESC_LEN -#include "osdep.h" -#include "new_baseclass.h" - -// Flags to indicate current "load" state of plugin. -// NOTE: order is important, as greater/less comparisons are made. -typedef enum { - PL_EMPTY = 0, // empty slot - PL_VALID, // has valid info in it - PL_BADFILE, // nonexistent file (open failed), - // or not a valid plugin file (query failed) - PL_OPENED, // dlopened and queried - PL_FAILED, // opened, but failed to attach or unattach - PL_RUNNING, // attached and running - PL_PAUSED, // attached but paused -} PLUG_STATUS; - -// Action to take for plugin at next opportunity. -typedef enum { - PA_NULL = 0, - PA_NONE, // no action needed right now - PA_KEEP, // keep, after ini refresh - PA_LOAD, // load (dlopen, query) and try to attach - PA_ATTACH, // attach - PA_UNLOAD, // unload (detach, dlclose) - PA_RELOAD, // unload and load again -} PLUG_ACTION; - -// Flags to indicate from where the plugin was loaded. -typedef enum { - PS_INI = 0, // was loaded from the plugins.ini - PS_CMD, // was loaded via a server command - PS_PLUGIN, // was loaded by other plugin -} PLOAD_SOURCE; - -// Flags for how to word description of plugin loadtime. -typedef enum { - SL_SIMPLE = 0, // single word - SL_SHOW, // for "show" output, 5 chars - SL_ALLOWED, // when plugin is allowed to load/unload - SL_NOW, // current situation -} STR_LOADTIME; - -// Flags for how to format description of status. -typedef enum { - ST_SIMPLE = 0, // single word - ST_SHOW, // for "show" output, 4 chars -} STR_STATUS; - -// Flags for how to format description of action. -typedef enum { - SA_SIMPLE = 0, // single word - SA_SHOW, // for "show" output, 4 chars -} STR_ACTION; - -// Flags for how to format description of source. -typedef enum { - SO_SIMPLE = 0, // two words - SO_SHOW, // for "list" output, 3 chars -} STR_SOURCE; - -// api table list -typedef struct { - enginefuncs_t *engine; - DLL_FUNCTIONS *dllapi; - NEW_DLL_FUNCTIONS *newapi; -} api_tables_t; - -// An individual plugin. -class MPlugin : public class_metamod_new { - public: - // data: - // reordered for faster api_hook.cpp functions - PLUG_STATUS status; // current status of plugin (loaded, etc) - api_tables_t tables; - api_tables_t post_tables; - - inline DLLINTERNAL void * get_api_table(enum_api_t api) { - return(((void**)&tables)[api]); - } - inline DLLINTERNAL void * get_api_post_table(enum_api_t api) { - return(((void**)&post_tables)[api]); - } - - int index; // 1-based - int pfspecific; // level of specific platform affinity, used during load time - PLUG_ACTION action; // what to do with plugin (load, unload, etc) - PLOAD_SOURCE source; // source of the request to load the plugin - int source_plugin_index; // index of plugin that loaded this plugin. -1 means source plugin has been unloaded. - int unloader_index; - mBOOL is_unloader; // fix to prevent other plugins unload active unloader. - - DLHANDLE handle; // handle for dlopen, dlsym, etc - plugin_info_t *info; // information plugin provides about itself - time_t time_loaded; // when plugin was loaded - - char filename[PATH_MAX]; // ie "dlls/mm_test_i386.so", from inifile - char *file; // ie "mm_test_i386.so", ptr from filename - char desc[MAX_DESC_LEN]; // ie "Test metamod plugin", from inifile - char pathname[PATH_MAX]; // UNIQUE, ie "/home/willday/half-life/cstrike/dlls/mm_test_i386.so", built with GameDLL.gamedir - - // functions: - mBOOL DLLINTERNAL ini_parseline(const char *line); // parse line from inifile - mBOOL DLLINTERNAL cmd_parseline(const char *line); // parse from console command - mBOOL DLLINTERNAL plugin_parseline(const char *fname, int loader_index); // parse from plugin - mBOOL DLLINTERNAL check_input(void); - - mBOOL DLLINTERNAL resolve(void); // find a matching file on disk - char * DLLINTERNAL resolve_dirs(const char *path); - char * DLLINTERNAL resolve_prefix(const char *path); - char * DLLINTERNAL resolve_suffix(const char *path); - static mBOOL DLLINTERNAL is_platform_postfix(const char *pf); - - mBOOL DLLINTERNAL platform_match(MPlugin* plugin); - - mBOOL DLLINTERNAL load(PLUG_LOADTIME now); - mBOOL DLLINTERNAL unload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason, PL_UNLOAD_REASON real_reason); - mBOOL DLLINTERNAL reload(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); - mBOOL DLLINTERNAL pause(void); - mBOOL DLLINTERNAL unpause(void); - mBOOL DLLINTERNAL retry(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // if previously failed - void DLLINTERNAL free_api_pointers(void); - mBOOL DLLINTERNAL clear(void); - mBOOL DLLINTERNAL plugin_unload(plid_t plid, PLUG_LOADTIME now, PL_UNLOAD_REASON reason); // other plugin unloading - void DLLINTERNAL show(void); // print info about plugin to console - - mBOOL DLLINTERNAL newer_file(void); // check for newer file on disk - - // output string functions - const char * DLLINTERNAL str_status(STR_STATUS fmt); - const char * DLLINTERNAL str_action(STR_ACTION fmt); - const char * DLLINTERNAL str_source(STR_SOURCE fmt); - - const char * DLLINTERNAL str_reason(PL_UNLOAD_REASON preason, PL_UNLOAD_REASON preal_reason); - const char * DLLINTERNAL str_loadtime(PLUG_LOADTIME pallow, STR_LOADTIME fmt); - - inline const char * DLLINTERNAL str_status(void) { return(str_status(ST_SIMPLE)); }; - inline const char * DLLINTERNAL str_action(void) { return(str_action(SA_SIMPLE)); }; - inline const char * DLLINTERNAL str_source(void) { return(str_source(SO_SIMPLE)); }; - - inline const char * DLLINTERNAL str_loadable(void) { - return(info?str_loadtime(info->loadable, SL_SIMPLE):" -"); - }; - inline const char * DLLINTERNAL str_unloadable(void) { - return(info?str_loadtime(info->unloadable, SL_SIMPLE):" -"); - }; - inline const char * DLLINTERNAL str_loadable(STR_LOADTIME fmt) { - return(info?str_loadtime(info->loadable, fmt):" -"); - }; - inline const char * DLLINTERNAL str_unloadable(STR_LOADTIME fmt) { - return(info?str_loadtime(info->unloadable, fmt):" -"); - }; - private: - mBOOL DLLINTERNAL query(void); - mBOOL DLLINTERNAL attach(PLUG_LOADTIME now); - mBOOL DLLINTERNAL detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason); - - gamedll_funcs_t gamedll_funcs; - mutil_funcs_t mutil_funcs; -}; - -// Macros used by MPlugin::show(), to list the functions that the plugin -// catches. -#define SHOW_DEF_API(api_info, api_table, pre_str, post_str) \ - n=0; \ - { \ - const api_info_t * ainfo = (const api_info_t *)&api_info; \ - const void ** table = (const void **)api_table; \ - for(int i = 0; &ainfo[i] < &api_info.END; i++) { \ - if(table[i]) { \ - META_CONS("%s%s%s", pre_str, ainfo[i].name, post_str); \ - n++; \ - } \ - } \ - } - -#define SHOW_DEF_DLLAPI(api_table, pre_str, post_str) \ - SHOW_DEF_API(dllapi_info, api_table, pre_str, post_str) - -#define SHOW_DEF_NEWAPI(api_table, pre_str, post_str) \ - SHOW_DEF_API(newapi_info, api_table, pre_str, post_str) - -#define SHOW_DEF_ENGINE(api_table, pre_str, post_str) \ - SHOW_DEF_API(engine_info, api_table, pre_str, post_str) - -#endif /* MPLUGIN_H */ diff --git a/src/mreg.h b/src/mreg.h deleted file mode 100644 index 7421a2d..0000000 --- a/src/mreg.h +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef MREG_H -#define MREG_H - -#include "types_meta.h" // mBOOL -#include "comp_dep.h" // -#include "new_baseclass.h" - -// Number of entries to add to reglists when they need to grow. Typically -// more cvars than commands, so we grow them at different increments. -#define REG_CMD_GROWSIZE 32 -#define REG_CVAR_GROWSIZE 64 - -// Width required to printf a Reg*List index number, for show() functions. -// This used to correspond to the number of digits in MAX_REG, which was a -// fixed, compile-time limit. However, now that the reg lists are grown -// dynamically, this has less strong correspondance to list sizes. So for -// the moment, it reflects what one might normally expect to be the max -// width needed to print an index number; 4 allows 9999 (which is a damn -// lot, if you ask me). -#define WIDTH_MAX_REG 4 - -// Max number of registered user msgs we can manage. -#define MAX_REG_MSGS 256 - -// Max number of clients on server -#define MAX_CLIENTS_CONNECTED 32 - -// Flags to indicate if given cvar or func is part of a loaded plugin. -typedef enum { - RG_INVALID, - RG_VALID, -} REG_STATUS; - -// Pointer to function registered by AddServerCommand. -typedef void (*REG_CMD_FN) (void); - - -// An individual registered function/command. -class MRegCmd : public class_metamod_new { - friend class MRegCmdList; - private: - // data: - int index; // 1-based - public: - char *name; // space is malloc'd - REG_CMD_FN pfnCmd; // pointer to the function - int plugid; // index id of corresponding plugin - REG_STATUS status; // whether corresponding plugin is loaded - // functions: - void DLLINTERNAL init(int idx); // init values, as not using constructors - mBOOL DLLINTERNAL call(void); // try to call the function -}; - - -// A list of registered commands. -class MRegCmdList : public class_metamod_new { - private: - // data: - MRegCmd *mlist; // malloc'd array of registered commands - int size; // current size of list - int endlist; // index of last used entry - // Private; to satisfy -Weffc++ "has pointer data members but does - // not override" copy/assignment constructor. - void operator=(const MRegCmdList &src); - MRegCmdList(const MRegCmdList &src); - - public: - // constructor: - MRegCmdList(void) DLLINTERNAL; - - // functions: - MRegCmd * DLLINTERNAL find(const char *findname); // find by MRegCmd->name - MRegCmd * DLLINTERNAL add(const char *addname); - void DLLINTERNAL disable(int plugin_id); // change status to Invalid - void DLLINTERNAL show(void); // list all funcs to console - void DLLINTERNAL show(int plugin_id); // list given plugin's funcs to console -}; - - - -// An individual registered cvar. -class MRegCvar : public class_metamod_new { - friend class MRegCvarList; - private: - // data: - int index; // 1-based - public: - cvar_t *data; // actual cvar structure, malloc'd - int plugid; // index id of corresponding plugin - REG_STATUS status; // whether corresponding plugin is loaded - // functions: - void DLLINTERNAL init(int idx); // init values, as not using constructors - mBOOL DLLINTERNAL set(cvar_t *src); -}; - - -// A list of registered cvars. -class MRegCvarList : public class_metamod_new { - private: - // data: - MRegCvar *vlist; // malloc'd array of registered cvars - int size; // size of list, ie MAX_REG_CVARS - int endlist; // index of last used entry - // Private; to satisfy -Weffc++ "has pointer data members but does - // not override" copy/assignment constructor. - void operator=(const MRegCvarList &src); - MRegCvarList(const MRegCvarList &src); - - public: - // constructor: - MRegCvarList(void) DLLINTERNAL; - - // functions: - MRegCvar * DLLINTERNAL add(const char *addname); - MRegCvar * DLLINTERNAL find(const char *findname); // find by MRegCvar->data.name - void DLLINTERNAL disable(int plugin_id); // change status to Invalid - void DLLINTERNAL show(void); // list all cvars to console - void DLLINTERNAL show(int plugin_id); // list given plugin's cvars to console -}; - - - -// An individual registered user msg, from gamedll. -class MRegMsg : public class_metamod_new { - friend class MRegMsgList; - private: - // data: - int index; // 1-based - public: - const char *name; // name, assumed constant string in gamedll - int msgid; // msgid, assigned by engine - int size; // size, if given by gamedll -}; - - -// A list of registered user msgs. -class MRegMsgList : public class_metamod_new { - private: - // data: - MRegMsg mlist[MAX_REG_MSGS]; // array of registered msgs - int size; // size of list, ie MAX_REG_MSGS - int endlist; // index of last used entry - - public: - // constructor: - MRegMsgList(void) DLLINTERNAL; - - // functions: - MRegMsg * DLLINTERNAL add(const char *addname, int addmsgid, int addsize); - MRegMsg * DLLINTERNAL find(const char *findname); - MRegMsg * DLLINTERNAL find(int findmsgid); - void DLLINTERNAL show(void); // list all msgs to console -}; - -#endif /* MREG_H */ diff --git a/src/new_baseclass.h b/src/new_baseclass.h deleted file mode 100644 index 3fad990..0000000 --- a/src/new_baseclass.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef METAMOD_NEW_BASECLASS_H -#define METAMOD_NEW_BASECLASS_H - -#include - -#include "comp_dep.h" - -//new/delete operators with malloc/free to remove need for libstdc++ - -class class_metamod_new { -public: - // Construction - class_metamod_new(void) { }; - // Operators - inline void * operator new(size_t size) - { - if(size==0) - return(calloc(1, 1)); - return(calloc(1, size)); - } - - inline void * operator new[](size_t size) - { - if(size==0) - return(calloc(1, 1)); - return(calloc(1, size)); - } - - inline void operator delete(void *ptr) - { - if(ptr) - free(ptr); - } - - inline void operator delete[](void *ptr) - { - if(ptr) - free(ptr); - } -}; - -#endif /*METAMOD_NEW_BASECLASS_H*/ diff --git a/src/osdep_linkent_win32.cpp b/src/osdep_linkent_win32.cpp deleted file mode 100644 index 0a39acc..0000000 --- a/src/osdep_linkent_win32.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include // always -#include "osdep.h" -#include "log_meta.h" // META_LOG, etc -#include "support_meta.h" - - -// -// Win32 code for dynamic linkents -// -- by Jussi Kivilinna -// - -// -// Reads metamod.dll and game.dll function export tables and combines theim to -// single table that replaces metamod.dll's original table. -// - -typedef struct sort_names_s { - unsigned long name; - unsigned short nameOrdinal; -} sort_names_t; - -//relative virtual address to virtual address -#define rva_to_va(base, rva) ((unsigned long)base + (unsigned long)rva) -//virtual address to relative virtual address -#define va_to_rva(base, va) ((unsigned long)va - (unsigned long)base) - -// -// Checks module signatures and return ntheaders pointer for valid module -// -static IMAGE_NT_HEADERS * DLLINTERNAL_NOVIS get_ntheaders(HMODULE module) -{ - union { - unsigned long mem; - IMAGE_DOS_HEADER * dos; - IMAGE_NT_HEADERS * pe; - } mem; - - //Check if valid dos header - mem.mem = (unsigned long)module; - if(IsBadReadPtr(mem.dos, sizeof(*mem.dos)) || mem.dos->e_magic != IMAGE_DOS_SIGNATURE) - return(0); - - //Get and check pe header - mem.mem = rva_to_va(module, mem.dos->e_lfanew); - if(IsBadReadPtr(mem.pe, sizeof(*mem.pe)) || mem.pe->Signature != IMAGE_NT_SIGNATURE) - return(0); - - return(mem.pe); -} - -// -// Returns export table for valid module -// -static IMAGE_EXPORT_DIRECTORY * DLLINTERNAL_NOVIS get_export_table(HMODULE module) -{ - union { - unsigned long mem; - void * pvoid; - IMAGE_DOS_HEADER * dos; - IMAGE_NT_HEADERS * pe; - IMAGE_EXPORT_DIRECTORY * export_dir; - } mem; - - //Check module - mem.pe = get_ntheaders(module); - if(!mem.pe) - return(0); - - //Check for exports - if(!mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) - return(0); - - mem.mem = rva_to_va(module, mem.pe->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - if(IsBadReadPtr(mem.export_dir, sizeof(*mem.export_dir))) - return(0); - - return(mem.export_dir); -} - -// -// Sort function for qsort -// -static int sort_names_list(const sort_names_t * A, const sort_names_t * B) -{ - const char * str_A = (const char *)A->name; - const char * str_B = (const char *)B->name; - - return(mm_strcmp(str_A, str_B)); -} - -// -// Combines moduleMM and moduleGame export tables and replaces moduleMM table with new one -// -static int DLLINTERNAL_NOVIS combine_module_export_tables(HMODULE moduleMM, HMODULE moduleGame) -{ - IMAGE_EXPORT_DIRECTORY * exportMM; - IMAGE_EXPORT_DIRECTORY * exportGame; - - unsigned long newNumberOfFunctions; - unsigned long newNumberOfNames; - unsigned long * newFunctions; - unsigned long * newNames; - unsigned short * newNameOrdinals; - sort_names_t * newSort; - - unsigned long i; - unsigned long u; - unsigned long funcCount; - unsigned long nameCount; - unsigned long listFix; - - //Get export tables - exportMM = get_export_table(moduleMM); - exportGame = get_export_table(moduleGame); - if(!exportMM || !exportGame) - { - META_ERROR("Couldn't initialize dynamic linkents, exportMM: %i, exportGame: %i. Exiting...", exportMM, exportGame); - return(0); - } - - //setup new export table - newNumberOfFunctions = exportMM->NumberOfFunctions + exportGame->NumberOfFunctions; - newNumberOfNames = exportMM->NumberOfNames + exportGame->NumberOfNames; - - //alloc lists - *(void**)&newFunctions = calloc(1, newNumberOfFunctions * sizeof(*newFunctions)); - *(void**)&newSort = calloc(1, newNumberOfNames * sizeof(*newSort)); - - //copy moduleMM to new export - for(funcCount = 0; funcCount < exportMM->NumberOfFunctions; funcCount++) - newFunctions[funcCount] = rva_to_va(moduleMM, ((unsigned long*)rva_to_va(moduleMM, exportMM->AddressOfFunctions))[funcCount]); - for(nameCount = 0; nameCount < exportMM->NumberOfNames; nameCount++) - { - //fix name address - newSort[nameCount].name = rva_to_va(moduleMM, ((unsigned long*)rva_to_va(moduleMM, exportMM->AddressOfNames))[nameCount]); - //ordinal is index to function list - newSort[nameCount].nameOrdinal = ((unsigned short *)rva_to_va(moduleMM, exportMM->AddressOfNameOrdinals))[nameCount]; - } - - //copy moduleGame to new export - for(i = 0; i < exportGame->NumberOfFunctions; i++) - newFunctions[funcCount + i] = rva_to_va(moduleGame, ((unsigned long*)rva_to_va(moduleGame, exportGame->AddressOfFunctions))[i]); - for(i = 0, listFix = 0; i < exportGame->NumberOfNames; i++) - { - const char * name = (const char *)rva_to_va(moduleGame, ((unsigned long*)rva_to_va(moduleGame, exportGame->AddressOfNames))[i]); - //Check if name already in the list - for(u = 0; u < nameCount; u++) - { - if(!strcasecmp(name, (const char*)newSort[u].name)) - { - listFix -= 1; - break; - } - } - if(u < nameCount) //already in the list.. skip - continue; - - newSort[nameCount + i + listFix].name = (unsigned long)name; - newSort[nameCount + i + listFix].nameOrdinal = (unsigned short)funcCount + ((unsigned short *)rva_to_va(moduleGame, exportGame->AddressOfNameOrdinals))[i]; - } - - //set new number - newNumberOfNames = nameCount + i + listFix; - - //sort names list - qsort(newSort, newNumberOfNames, sizeof(*newSort), (int(*)(const void*, const void*))&sort_names_list); - - //make newNames and newNameOrdinals lists (VirtualAlloc so we dont waste heap memory to stuff that isn't freed) - *(void**)&newNames = VirtualAlloc(0, newNumberOfNames * sizeof(*newNames), MEM_COMMIT, PAGE_READWRITE); - *(void**)&newNameOrdinals = VirtualAlloc(0, newNumberOfNames * sizeof(*newNameOrdinals), MEM_COMMIT, PAGE_READWRITE); - - for(i = 0; i < newNumberOfNames; i++) - { - newNames[i] = newSort[i].name; - newNameOrdinals[i] = newSort[i].nameOrdinal; - } - - free(newSort); - - //translate VAs to RVAs - for(i = 0; i < newNumberOfFunctions; i++) - newFunctions[i] = va_to_rva(moduleMM, newFunctions[i]); - for(i = 0; i < newNumberOfNames; i++) - { - newNames[i] = va_to_rva(moduleMM, newNames[i]); - newNameOrdinals[i] = (unsigned short)va_to_rva(moduleMM, newNameOrdinals[i]); - } - - DWORD OldProtect; - if(!VirtualProtect(exportMM, sizeof(*exportMM), PAGE_READWRITE, &OldProtect)) - { - META_ERROR("Couldn't initialize dynamic linkents, VirtualProtect failed: %i. Exiting...", GetLastError()); - return(0); - } - - exportMM->Base = 1; - exportMM->NumberOfFunctions = newNumberOfFunctions; - exportMM->NumberOfNames = newNumberOfNames; - *(unsigned long*)&(exportMM->AddressOfFunctions) = va_to_rva(moduleMM, newFunctions); - *(unsigned long*)&(exportMM->AddressOfNames) = va_to_rva(moduleMM, newNames); - *(unsigned long*)&(exportMM->AddressOfNameOrdinals) = va_to_rva(moduleMM, newNameOrdinals); - - VirtualProtect(exportMM, sizeof(*exportMM), OldProtect, &OldProtect); - return(1); -} - -// -// ... -// -int DLLINTERNAL init_linkent_replacement(DLHANDLE moduleMetamod, DLHANDLE moduleGame) -{ - return(combine_module_export_tables(moduleMetamod, moduleGame)); -} diff --git a/src/osdep_p.cpp b/src/osdep_p.cpp deleted file mode 100644 index f0b643e..0000000 --- a/src/osdep_p.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#ifdef linux -// enable extra routines in system header files, like dladdr -# ifndef _GNU_SOURCE -# define _GNU_SOURCE -# endif -#include // dlopen, dladdr, etc -#endif /* linux */ - -#include // always -#include "osdep_p.h" // me -#include "support_meta.h" // STRNCPY - - -#ifdef _WIN32 -// MSVC doesn't provide "dirent.h" header. These functions wrap opendir/readdir/closedir -// functions to FindFirst/FindNext/FindClose win32api-functions. -DIR * DLLINTERNAL my_opendir(const char *path) -{ - char search_path[MAX_PATH]; - DIR *dir; - - // Add wildcards to path - safevoid_snprintf(search_path, sizeof(search_path), "%s\\*.*", path); - - // Get memory for new DIR object - dir = (DIR*)calloc(1, sizeof(DIR)); - - // Start searching - dir->handle = FindFirstFileA(search_path, &dir->find_data); - if(dir->handle == INVALID_HANDLE_VALUE) { - free(dir); - return(0); - } - - // Found file - dir->not_found = 0; - - return(dir); -} - -struct dirent * DLLINTERNAL my_readdir(DIR *dir) -{ - // If not found stop - if(!dir || dir->not_found) - return(0); - - // Set filename - STRNCPY(dir->ent.d_name, dir->find_data.cFileName, sizeof(dir->ent.d_name)); - - // Search next - dir->not_found = !FindNextFileA(dir->handle, &dir->find_data); - - return(&dir->ent); -} - -void DLLINTERNAL my_closedir(DIR *dir) -{ - if(!dir) - return; - - FindClose(dir->handle); - free(dir); -} -#endif /* _WIN32 */ - -//get module handle of memptr -#ifdef linux -DLHANDLE DLLINTERNAL get_module_handle_of_memptr(void * memptr) -{ - Dl_info dli; - Q_memset(&dli, 0, sizeof(dli)); - - if(dladdr(memptr, &dli)) - return(dlopen(dli.dli_fname, RTLD_NOW)); - else - return((void*)0); -} -#else -DLHANDLE DLLINTERNAL get_module_handle_of_memptr(void * memptr) -{ - MEMORY_BASIC_INFORMATION MBI; - - if(!VirtualQuery(memptr, &MBI, sizeof(MBI))) - return(NULL); - if(MBI.State != MEM_COMMIT) - return(NULL); - if(!MBI.AllocationBase) - return(NULL); - - return((DLHANDLE)MBI.AllocationBase); -} -#endif /* linux */ diff --git a/src/osdep_p.h b/src/osdep_p.h deleted file mode 100644 index 00c9863..0000000 --- a/src/osdep_p.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef OSDEP_P_H -#define OSDEP_P_H - -#include "types_meta.h" // mBOOL -#include "osdep.h" // PATH_MAX - -// Checks if file is hlsdk api game dll -// (osdep_detect_gamedll_linux.cpp and osdep_detect_gamedll_win32.cpp) -// --Jussi Kivilinna -mBOOL DLLINTERNAL is_gamedll(const char *filename); - -// MSVC doesn't provide opendir/readdir/closedir, so we write our own. -// --Jussi Kivilinna -#ifdef _WIN32 - struct my_dirent { - char d_name[PATH_MAX]; - }; - typedef struct { - HANDLE handle; - WIN32_FIND_DATAA find_data; - struct my_dirent ent; - int not_found; - } my_DIR; - - #define dirent my_dirent - #define DIR my_DIR - - DIR * DLLINTERNAL my_opendir(const char *); - struct dirent * DLLINTERNAL my_readdir(DIR *); - void DLLINTERNAL my_closedir(DIR *); - - #define opendir(x) my_opendir(x) - #define readdir(x) my_readdir(x) - #define closedir(x) my_closedir(x) -#else - #include -#endif /* _WIN32 */ - -DLHANDLE DLLINTERNAL get_module_handle_of_memptr(void * memptr); - -#ifdef linux - void * DLLINTERNAL get_dlsym_pointer(void); -#endif - -#endif /* OSDEP_P_H */ diff --git a/src/reg_support.h b/src/reg_support.h deleted file mode 100644 index f06be51..0000000 --- a/src/reg_support.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef REG_SUPPORT_H -#define REG_SUPPORT_H - -#include "mreg.h" // REG_CMD_FN, etc - -// these are only 'hidden' because called from outside (plugins and engine) -void DLLHIDDEN meta_command_handler(void); -void DLLHIDDEN meta_AddServerCommand(const char *cmd_name, REG_CMD_FN function); -void DLLHIDDEN meta_CVarRegister(cvar_t *pCvar); -int DLLHIDDEN meta_RegUserMsg(const char *pszName, int iSize); -void DLLHIDDEN meta_QueryClientCvarValue(const edict_t *player, const char *cvarName); - -#endif /* REG_SUPPORT_H */ diff --git a/src/sdk_util.cpp b/src/sdk_util.cpp deleted file mode 100644 index d6a28f9..0000000 --- a/src/sdk_util.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include "sdk_util.h" -#include // for strncpy(), etc -#include "osdep.h" // win32 vsnprintf, etc - -const char * DLLINTERNAL META_UTIL_VarArgs(const char *format, ...) -{ - va_list argptr; - static char string[4096]; - va_start(argptr, format); - safevoid_vsnprintf(string, sizeof(string), format, argptr); - va_end(argptr); - return(string); -} - -short DLLINTERNAL FixedSigned16(float value, float scale) -{ - int output; - output = (int)(value * scale); - if(output > 32767) - output = 32767; - if(output < -32768) - output = -32768; - return((short)output); -} - -unsigned short DLLINTERNAL FixedUnsigned16(float value, float scale) -{ - int output; - output = (int)(value * scale); - if(output < 0) - output = 0; - if(output > 0xFFFF) - output = 0xFFFF; - return((unsigned short)output); -} - - -void DLLINTERNAL META_UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage) -{ - if (fast_FNullEnt(pEntity) || pEntity->free) - { - return; - } - MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity ); - WRITE_BYTE( TE_TEXTMESSAGE ); - WRITE_BYTE( textparms.channel & 0xFF ); - WRITE_SHORT( FixedSigned16( textparms.x, 1<<13 ) ); - WRITE_SHORT( FixedSigned16( textparms.y, 1<<13 ) ); - WRITE_BYTE( textparms.effect ); - WRITE_BYTE( textparms.r1 ); - WRITE_BYTE( textparms.g1 ); - WRITE_BYTE( textparms.b1 ); - WRITE_BYTE( textparms.a1 ); - WRITE_BYTE( textparms.r2 ); - WRITE_BYTE( textparms.g2 ); - WRITE_BYTE( textparms.b2 ); - WRITE_BYTE( textparms.a2 ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1<<8 ) ); - WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1<<8 ) ); - if (textparms.effect == 2) - { - WRITE_SHORT(FixedUnsigned16(textparms.fxTime, 1 << 8)); - } - if(Q_strlen( pMessage ) < 512) - { - WRITE_STRING( pMessage ); - } else { - char tmp[512]; - Q_strncpy( tmp, pMessage, 511 ); - tmp[511] = 0; - WRITE_STRING( tmp ); - } - MESSAGE_END(); -} diff --git a/src/tqueue.h b/src/tqueue.h deleted file mode 100644 index cc9c721..0000000 --- a/src/tqueue.h +++ /dev/null @@ -1,114 +0,0 @@ -// vi: set ts=4 sw=4 : -// vim: set tw=75 : - -// tqueue.h - template classes for Queue and QItem - -/* - * Copyright (c) 2001-2006 Will Day - * - * This file is part of Metamod. - * - * Metamod is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * Metamod is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Metamod; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, the author gives permission to - * link the code of this program with the Half-Life Game Engine ("HL - * Engine") and Modified Game Libraries ("MODs") developed by Valve, - * L.L.C ("Valve"). You must obey the GNU General Public License in all - * respects for all of the code used other than the HL Engine and MODs - * from Valve. If you modify this file, you may extend this exception - * to your version of the file, but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. - * - */ -/* -#ifndef TQUEUE_H -#define TQUEUE_H - -#include "new_baseclass.h" - -// Forward declarations. -template class Queue; - -// Template for Queue. -template class Queue : public class_metamod_new { - private: - // private copy/assign constructors: - Queue(const Queue &src); - void operator=(const Queue &src); - protected: - // structs: - class QItem : public class_metamod_new { - private: - // private copy/assign constructors: - QItem(const QItem &src); - void operator=(const QItem &src); - public: - qdata_t *data; - QItem *next; - QItem(void) :data(NULL), next(NULL) { }; - QItem(qdata_t *dnew) :data(dnew), next(NULL) { }; - }; - // data: - int size; - QItem *front; - QItem *end; - public: - // constructor: - Queue(void) :size(0), front(NULL), end(NULL) {}; - // functions: - void push(qdata_t *qadd); - qdata_t * pop(void); -}; - - -///// Template Queue: - -// Push onto the queue (at end). -template inline void Queue::push(qdata_t *qadd) { - QItem *qnew = new QItem(qadd); - - if(size==0) - front=qnew; - else - end->next=qnew; - - end=qnew; - - size++; -} - -// Pop from queue (from front). Wait for an item to actually be available -// on the queue (block until there's something there). -template inline qdata_t* Queue::pop(void) { - QItem *qtmp; - qdata_t *ret; - - if(size==0) - return(NULL); - - qtmp=front; - - ret=front->data; - front=front->next; - - delete qtmp; - - size--; - - return(ret); -} - -#endif*/ /* TQUEUE_H */ diff --git a/src/vdate.cpp b/src/vdate.cpp deleted file mode 100644 index f34347e..0000000 --- a/src/vdate.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "info_name.h" // for VNAME, VVERSION, etc -#include "vdate.h" - - -// Grab date/time of compile. The Makefile is set up to recompile this -// module before each link, so that this will always indicate the time the -// library was compiled and linked. - -// This is in a separate file from vers_*, so it can be generically used by -// multiple projects. - -char const *COMPILE_TIME=__DATE__ ", " __TIME__; - -#ifndef COMPILE_TZ - #define COMPILE_TZ "EET" -#endif - -char const *COMPILE_TZONE = COMPILE_TZ; - -// Include a string for /usr/bin/ident. - -char const *vstring="\n$Pg: " VNAME " -- " VVERSION " | " __DATE__ " - " __TIME__ " $\n"; diff --git a/src/vdate.h b/src/vdate.h deleted file mode 100644 index 50f8a11..0000000 --- a/src/vdate.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef VDATE_H -#define VDATE_H - -#include "comp_dep.h" - -extern char const *COMPILE_TIME DLLHIDDEN; -extern char const *COMPILE_TZONE DLLHIDDEN; - -#endif /* VDATE_H */ diff --git a/src/vers_meta.h b/src/vers_meta.h deleted file mode 100644 index 7d3f8ac..0000000 --- a/src/vers_meta.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef VERS_META_H -#define VERS_META_H - -#ifndef OPT_TYPE -#define OPT_TYPE "SSE" -#endif /* not OPT_TYPE */ - - -#define VDATE "2013/05/30" -#define VPATCH_COPYRIGHT_YEAR "2013" -#define VMETA_VERSION "2.0" - -#define VPATCH_NAME "Metamod-P (mm-p)" -#define VPATCH_IVERSION 38 -#define VPATCH_VERSION "38" -#define VPATCH_AUTHOR "Jussi Kivilinna" -#define VPATCH_WEBSITE "http://metamod-p.sourceforge.net/" - -#define VVERSION VMETA_VERSION "p" VPATCH_VERSION -#define RC_VERS_DWORD 2,0,0,VPATCH_IVERSION // Version Windows DLL Resources in res_meta.rc - - -#define VPATCH_MODIFICATION "1" - - -#endif /* VERS_META_H */